]> git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/BIP39.git/blobdiff - src/js/index.js
xpub key can be used as bip32 root key
[perso/Immae/Projets/Cryptomonnaies/BIP39.git] / src / js / index.js
index 82e216179bcc98da895753338f38015575be2a36..45edea8477b835245c3a03b34183310f226ebbc3 100644 (file)
@@ -13,6 +13,7 @@
     var showAddress = true;
     var showPubKey = true;
     var showPrivKey = true;
+    var showQr = false;
 
     var entropyChangeTimeoutEvent = null;
     var phraseChangeTimeoutEvent = null;
@@ -50,6 +51,8 @@
     DOM.bip44purpose = $("#bip44 .purpose");
     DOM.bip44coin = $("#bip44 .coin");
     DOM.bip44account = $("#bip44 .account");
+    DOM.bip44accountXprv = $("#bip44 .account-xprv");
+    DOM.bip44accountXpub = $("#bip44 .account-xpub");
     DOM.bip44change = $("#bip44 .change");
     DOM.generatedStrength = $(".generate-container .strength");
     DOM.hardenedAddresses = $(".hardened-addresses");
     DOM.publicKeyToggle = $(".public-key-toggle");
     DOM.privateKeyToggle = $(".private-key-toggle");
     DOM.languages = $(".languages a");
+    DOM.qrContainer = $(".qr-container");
+    DOM.qrHider = DOM.qrContainer.find(".qr-hider");
+    DOM.qrImage = DOM.qrContainer.find(".qr-image");
+    DOM.qrHint = DOM.qrContainer.find(".qr-hint");
+    DOM.showQrEls = $("[data-show-qr]");
 
     function init() {
         // Events
@@ -87,6 +95,7 @@
         DOM.publicKeyToggle.on("click", togglePublicKeys);
         DOM.privateKeyToggle.on("click", togglePrivateKeys);
         DOM.languages.on("click", languageChanged);
+        setQrEvents(DOM.showQrEls);
         disableForms();
         hidePending();
         hideValidationError();
         // Calculate and display
         calcBip32RootKeyFromBase58(rootKeyBase58);
         calcForDerivationPath();
-        hidePending();
     }
 
     function calcForDerivationPath() {
         showPending();
+        clearAddressesList();
         hideValidationError();
         // Get the derivation path
         var derivationPath = getDerivationPath();
             showValidationError(errorText);
             return;
         }
-        calcBip32ExtendedKey(derivationPath);
+        bip32ExtendedKey = calcBip32ExtendedKey(derivationPath);
+        if (bip44TabSelected()) {
+            displayBip44Info();
+        }
         displayBip32Info();
         hidePending();
     }
     }
 
     function calcBip32ExtendedKey(path) {
-        bip32ExtendedKey = bip32RootKey;
+        var extendedKey = bip32RootKey;
         // Derive the key from the path
         var pathBits = path.split("/");
         for (var i=0; i<pathBits.length; i++) {
                 continue;
             }
             var hardened = bit[bit.length-1] == "'";
-            if (hardened) {
-                bip32ExtendedKey = bip32ExtendedKey.deriveHardened(index);
+            var isPriv = "privKey" in extendedKey;
+            var invalidDerivationPath = hardened && !isPriv;
+            if (invalidDerivationPath) {
+                extendedKey = null;
+            }
+            else if (hardened) {
+                extendedKey = extendedKey.deriveHardened(index);
             }
             else {
-                bip32ExtendedKey = bip32ExtendedKey.derive(index);
+                extendedKey = extendedKey.derive(index);
             }
         }
+        return extendedKey
     }
 
     function showValidationError(errorText) {
     }
 
     function getDerivationPath() {
-        if (DOM.bip44tab.hasClass("active")) {
+        if (bip44TabSelected()) {
             var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
             var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
             var account = parseIntNoNaN(DOM.bip44account.val(), 0);
             console.log("Using derivation path from BIP44 tab: " + derivationPath);
             return derivationPath;
         }
-        else if (DOM.bip32tab.hasClass("active")) {
+        else if (bip32TabSelected()) {
             var derivationPath = DOM.bip32path.val();
             console.log("Using derivation path from BIP32 tab: " + derivationPath);
             return derivationPath;
                 }
             }
         }
+        // Check no hardened derivation path when using xpub keys
+        var hardened = path.indexOf("'") > -1;
+        var isXpubkey = !("privKey" in bip32RootKey);
+        if (hardened && isXpubkey) {
+            return "Hardened derivation path is invalid with xpub key";
+        }
         return false;
     }
 
+    function displayBip44Info() {
+        // Get the derivation path for the account
+        var purpose = parseIntNoNaN(DOM.bip44purpose.val(), 44);
+        var coin = parseIntNoNaN(DOM.bip44coin.val(), 0);
+        var account = parseIntNoNaN(DOM.bip44account.val(), 0);
+        var path = "m/";
+        path += purpose + "'/";
+        path += coin + "'/";
+        path += account + "'/";
+        // Calculate the account extended keys
+        var accountExtendedKey = calcBip32ExtendedKey(path);
+        var accountXprv = accountExtendedKey.toBase58();
+        var accountXpub = accountExtendedKey.toBase58(false);
+        // Display the extended keys
+        DOM.bip44accountXprv.val(accountXprv);
+        DOM.bip44accountXpub.val(accountXpub);
+    }
+
     function displayBip32Info() {
         // Display the key
         DOM.seed.val(seed);
         var rootKey = bip32RootKey.toBase58();
         DOM.rootKey.val(rootKey);
-        var extendedPrivKey = bip32ExtendedKey.toBase58();
+        var xprvkeyB58 = "NA";
+        if (bip32ExtendedKey.privKey) {
+            xprvkeyB58 = bip32ExtendedKey.toBase58();
+        }
+        var extendedPrivKey = xprvkeyB58;
         DOM.extendedPrivKey.val(extendedPrivKey);
         var extendedPubKey = bip32ExtendedKey.toBase58(false);
         DOM.extendedPubKey.val(extendedPubKey);
                     key = bip32ExtendedKey.derive(index);
                 }
                 var address = key.getAddress().toString();
-                var privkey = key.privKey.toWIF(network);
+                var privkey = "NA";
+                if (key.privKey) {
+                    privkey = key.privKey.toWIF(network);
+                }
                 var pubkey = key.pubKey.toHex();
                 var indexText = getDerivationPath() + "/" + index;
                 if (useHardenedAddresses) {
             privkeyCell.addClass("invisible");
         }
         DOM.addresses.append(row);
+        var rowShowQrEls = row.find("[data-show-qr]");
+        setQrEvents(rowShowQrEls);
     }
 
     function hasStrongRandom() {
         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.qrHider.addClass("hidden");
+            }
+            else {
+                DOM.qrHider.removeClass("hidden");
+            }
+            DOM.qrContainer.removeClass("hidden");
+        }
+    }
+
+    function destroyQr() {
+        DOM.qrImage.text("");
+        DOM.qrContainer.addClass("hidden");
+    }
+
+    function toggleQr() {
+        showQr = !showQr;
+        DOM.qrHider.toggleClass("hidden");
+        DOM.qrHint.toggleClass("hidden");
+    }
+
+    function bip44TabSelected() {
+        return DOM.bip44tab.hasClass("active");
+    }
+
+    function bip32TabSelected() {
+        return DOM.bip32tab.hasClass("active");
+    }
+
     var networks = [
         {
             name: "Bitcoin",