From e00964ccf7a556895784ed05f0fdec954f5558d5 Mon Sep 17 00:00:00 2001 From: Ian Coleman Date: Thu, 1 Dec 2016 10:54:33 +1100 Subject: [PATCH] QR code shown on hover for certain bits of data QR code shown for: * mnemonic * seed * root key * derived extended private key * derived extended public key * addresses * public keys * private keys --- bip39-standalone.html | 102 +++++++++++++++++++++++++++++++++--- src/index.html | 37 ++++++++++--- src/js/index.js | 37 +++++++++++++ src/js/jquery.qrcode.min.js | 28 ++++++++++ tests.js | 44 ++++++++++++++++ 5 files changed, 232 insertions(+), 16 deletions(-) create mode 100644 src/js/jquery.qrcode.min.js diff --git a/bip39-standalone.html b/bip39-standalone.html index 0da2443..1d0e1cf 100644 --- a/bip39-standalone.html +++ b/bip39-standalone.html @@ -85,6 +85,20 @@ .card-suit.spade { color: #000; } + .qr-container { + position: fixed; + top: 0; + right: 0; + text-align: center; + background-color: #FFF; + border: 1px solid #CCC; + } + .qr-image { + margin: 5px; + } + .qr-hint { + padding: 2px; + } @@ -213,7 +227,7 @@
- +
@@ -225,7 +239,7 @@
- +
@@ -239,7 +253,7 @@
- +
@@ -386,13 +400,13 @@
- +
- +
@@ -590,6 +604,12 @@
+ + @@ -597,9 +617,9 @@ + + diff --git a/src/js/index.js b/src/js/index.js index 82e2161..5f688f0 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -13,6 +13,7 @@ var showAddress = true; var showPubKey = true; var showPrivKey = true; + var showQr = true; var entropyChangeTimeoutEvent = null; var phraseChangeTimeoutEvent = null; @@ -63,6 +64,10 @@ DOM.publicKeyToggle = $(".public-key-toggle"); DOM.privateKeyToggle = $(".private-key-toggle"); DOM.languages = $(".languages a"); + DOM.qrContainer = $(".qr-container"); + DOM.qrImage = DOM.qrContainer.find(".qr-image"); + DOM.qrHint = DOM.qrContainer.find(".qr-hint"); + DOM.showQrEls = $("[data-show-qr]"); function init() { // Events @@ -87,6 +92,7 @@ DOM.publicKeyToggle.on("click", togglePublicKeys); DOM.privateKeyToggle.on("click", togglePrivateKeys); DOM.languages.on("click", languageChanged); + setQrEvents(DOM.showQrEls); disableForms(); hidePending(); hideValidationError(); @@ -555,6 +561,8 @@ privkeyCell.addClass("invisible"); } DOM.addresses.append(row); + var rowShowQrEls = row.find("[data-show-qr]"); + setQrEvents(rowShowQrEls); } function hasStrongRandom() { @@ -902,6 +910,35 @@ return typeStr; } + function setQrEvents(els) { + els.on("mouseenter", createQr); + els.on("mouseleave", destroyQr); + els.on("click", toggleQr); + } + + function createQr(e) { + var content = e.target.textContent || e.target.value; + if (content) { + var size = 130; + DOM.qrImage.qrcode({width: size, height: size, text: content}); + if (!showQr) { + DOM.qrImage.addClass("hidden"); + } + DOM.qrContainer.removeClass("hidden"); + } + } + + function destroyQr() { + DOM.qrImage.text(""); + DOM.qrContainer.addClass("hidden"); + } + + function toggleQr() { + showQr = !showQr; + DOM.qrImage.toggleClass("hidden"); + DOM.qrHint.toggleClass("hidden"); + } + var networks = [ { name: "Bitcoin", diff --git a/src/js/jquery.qrcode.min.js b/src/js/jquery.qrcode.min.js new file mode 100644 index 0000000..1bfd0b0 --- /dev/null +++ b/src/js/jquery.qrcode.min.js @@ -0,0 +1,28 @@ +(function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.data=a}function o(a,c){this.typeNumber=a;this.errorCorrectLevel=c;this.modules=null;this.moduleCount=0;this.dataCache=null;this.dataList=[]}function q(a,c){if(void 0==a.length)throw Error(a.length+"/"+c);for(var d=0;da||this.moduleCount<=a||0>c||this.moduleCount<=c)throw Error(a+","+c);return this.modules[a][c]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){for(var a=1,a=1;40>a;a++){for(var c=p.getRSBlocks(a,this.errorCorrectLevel),d=new t,b=0,e=0;e=d;d++)if(!(-1>=a+d||this.moduleCount<=a+d))for(var b=-1;7>=b;b++)-1>=c+b||this.moduleCount<=c+b||(this.modules[a+d][c+b]= +0<=d&&6>=d&&(0==b||6==b)||0<=b&&6>=b&&(0==d||6==d)||2<=d&&4>=d&&2<=b&&4>=b?!0:!1)},getBestMaskPattern:function(){for(var a=0,c=0,d=0;8>d;d++){this.makeImpl(!0,d);var b=j.getLostPoint(this);if(0==d||a>b)a=b,c=d}return c},createMovieClip:function(a,c,d){a=a.createEmptyMovieClip(c,d);this.make();for(c=0;c=f;f++)for(var i=-2;2>=i;i++)this.modules[b+f][e+i]=-2==f||2==f||-2==i||2==i||0==f&&0==i?!0:!1}},setupTypeNumber:function(a){for(var c= +j.getBCHTypeNumber(this.typeNumber),d=0;18>d;d++){var b=!a&&1==(c>>d&1);this.modules[Math.floor(d/3)][d%3+this.moduleCount-8-3]=b}for(d=0;18>d;d++)b=!a&&1==(c>>d&1),this.modules[d%3+this.moduleCount-8-3][Math.floor(d/3)]=b},setupTypeInfo:function(a,c){for(var d=j.getBCHTypeInfo(this.errorCorrectLevel<<3|c),b=0;15>b;b++){var e=!a&&1==(d>>b&1);6>b?this.modules[b][8]=e:8>b?this.modules[b+1][8]=e:this.modules[this.moduleCount-15+b][8]=e}for(b=0;15>b;b++)e=!a&&1==(d>>b&1),8>b?this.modules[8][this.moduleCount- +b-1]=e:9>b?this.modules[8][15-b-1+1]=e:this.modules[8][15-b-1]=e;this.modules[this.moduleCount-8][8]=!a},mapData:function(a,c){for(var d=-1,b=this.moduleCount-1,e=7,f=0,i=this.moduleCount-1;0g;g++)if(null==this.modules[b][i-g]){var n=!1;f>>e&1));j.getMask(c,b,i-g)&&(n=!n);this.modules[b][i-g]=n;e--; -1==e&&(f++,e=7)}b+=d;if(0>b||this.moduleCount<=b){b-=d;d=-d;break}}}};o.PAD0=236;o.PAD1=17;o.createData=function(a,c,d){for(var c=p.getRSBlocks(a, +c),b=new t,e=0;e8*a)throw Error("code length overflow. ("+b.getLengthInBits()+">"+8*a+")");for(b.getLengthInBits()+4<=8*a&&b.put(0,4);0!=b.getLengthInBits()%8;)b.putBit(!1);for(;!(b.getLengthInBits()>=8*a);){b.put(o.PAD0,8);if(b.getLengthInBits()>=8*a)break;b.put(o.PAD1,8)}return o.createBytes(b,c)};o.createBytes=function(a,c){for(var d= +0,b=0,e=0,f=Array(c.length),i=Array(c.length),g=0;g>>=1;return c},getPatternPosition:function(a){return j.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,c,d){switch(a){case 0:return 0==(c+d)%2;case 1:return 0==c%2;case 2:return 0==d%3;case 3:return 0==(c+d)%3;case 4:return 0==(Math.floor(c/2)+Math.floor(d/3))%2;case 5:return 0==c*d%2+c*d%3;case 6:return 0==(c*d%2+c*d%3)%2;case 7:return 0==(c*d%3+(c+d)%2)%2;default:throw Error("bad maskPattern:"+ +a);}},getErrorCorrectPolynomial:function(a){for(var c=new q([1],0),d=0;dc)switch(a){case 1:return 10;case 2:return 9;case s:return 8;case 8:return 8;default:throw Error("mode:"+a);}else if(27>c)switch(a){case 1:return 12;case 2:return 11;case s:return 16;case 8:return 10;default:throw Error("mode:"+a);}else if(41>c)switch(a){case 1:return 14;case 2:return 13;case s:return 16;case 8:return 12;default:throw Error("mode:"+ +a);}else throw Error("type:"+c);},getLostPoint:function(a){for(var c=a.getModuleCount(),d=0,b=0;b=g;g++)if(!(0>b+g||c<=b+g))for(var h=-1;1>=h;h++)0>e+h||c<=e+h||0==g&&0==h||i==a.isDark(b+g,e+h)&&f++;5a)throw Error("glog("+a+")");return l.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;256<=a;)a-=255;return l.EXP_TABLE[a]},EXP_TABLE:Array(256), +LOG_TABLE:Array(256)},m=0;8>m;m++)l.EXP_TABLE[m]=1<m;m++)l.EXP_TABLE[m]=l.EXP_TABLE[m-4]^l.EXP_TABLE[m-5]^l.EXP_TABLE[m-6]^l.EXP_TABLE[m-8];for(m=0;255>m;m++)l.LOG_TABLE[l.EXP_TABLE[m]]=m;q.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var c=Array(this.getLength()+a.getLength()-1),d=0;d +this.getLength()-a.getLength())return this;for(var c=l.glog(this.get(0))-l.glog(a.get(0)),d=Array(this.getLength()),b=0;b>>7-a%8&1)},put:function(a,c){for(var d=0;d>>c-d-1&1))},getLengthInBits:function(){return this.length},putBit:function(a){var c=Math.floor(this.length/8);this.buffer.length<=c&&this.buffer.push(0);a&&(this.buffer[c]|=128>>>this.length%8);this.length++}};"string"===typeof h&&(h={text:h});h=r.extend({},{render:"canvas",width:256,height:256,typeNumber:-1, +correctLevel:2,background:"#ffffff",foreground:"#000000"},h);return this.each(function(){var a;if("canvas"==h.render){a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();var c=document.createElement("canvas");c.width=h.width;c.height=h.height;for(var d=c.getContext("2d"),b=h.width/a.getModuleCount(),e=h.height/a.getModuleCount(),f=0;f").css("width",h.width+"px").css("height",h.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",h.background);d=h.width/a.getModuleCount();b=h.height/a.getModuleCount();for(e=0;e").css("height",b+"px").appendTo(c);for(i=0;i").css("width", +d+"px").css("background-color",a.isDark(e,i)?h.foreground:h.background).appendTo(f)}}a=c;$(a).appendTo(this)})}})($); diff --git a/tests.js b/tests.js index 843078f..10d13a3 100644 --- a/tests.js +++ b/tests.js @@ -6,6 +6,11 @@ var page = require('webpage').create(); var url = 'src/index.html'; var testMaxTime = 10000; +page.viewportSize = { + width: 1024, + height: 720 +}; + page.onResourceError = function(e) { console.log("Error loading " + e.url); phantom.exit(); @@ -3042,6 +3047,45 @@ page.open(url, function(status) { }); }, +// Github issue 35 +// https://github.com/iancoleman/bip39/issues/35 +// QR Code support +function() { +page.open(url, function(status) { + // use entropy + page.evaluate(function() { + $(".generate").click(); + }); + waitForGenerate(function() { + var p = page.evaluate(function() { + // get position of mnemonic element + return $(".phrase").offset(); + }); + p.top = Math.ceil(p.top); + p.left = Math.ceil(p.left); + // check the qr code shows + page.sendEvent("mousemove", p.left+4, p.top+4); + var qrShowing = page.evaluate(function() { + return $(".qr-container").find("canvas").length > 0; + }); + if (!qrShowing) { + console.log("QR Code does not show"); + fail(); + } + // check the qr code hides + page.sendEvent("mousemove", p.left-4, p.top-4); + var qrHidden = page.evaluate(function() { + return $(".qr-container").find("canvas").length == 0; + }); + if (!qrHidden) { + console.log("QR Code does not hide"); + fail(); + } + next(); + }); +}); +}, + // If you wish to add more tests, do so here... -- 2.41.0