+ catch (e) {
+ return e.message;
+ }
+ // hex entropy is detected
+ try {
+ e = Entropy.fromString("0123456789ABCDEF");
+ if (e.base.str != "hexadecimal") {
+ return "hexadecimal entropy not detected correctly";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // card entropy is detected
+ try {
+ e = Entropy.fromString("AC4DTHKS");
+ if (e.base.str != "card") {
+ return "card entropy not detected correctly";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // entropy is case insensitive
+ try {
+ e = Entropy.fromString("aBcDeF");
+ if (e.cleanStr != "aBcDeF") {
+ return "Entropy should not be case sensitive";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // dice entropy is converted to base6
+ try {
+ e = Entropy.fromString("123456");
+ if (e.cleanStr != "123450") {
+ return "Dice entropy is not automatically converted to base6";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // dice entropy is preferred to base6 if ambiguous
+ try {
+ e = Entropy.fromString("12345");
+ if (e.base.str != "base 6 (dice)") {
+ return "dice not used as default over base 6";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // unused characters are ignored
+ try {
+ e = Entropy.fromString("fghijkl");
+ if (e.cleanStr != "f") {
+ return "additional characters are not ignored";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // the lowest base is used by default
+ // 7 could be decimal or hexadecimal, but should be detected as decimal
+ try {
+ e = Entropy.fromString("7");
+ if (e.base.str != "base 10") {
+ return "lowest base is not used";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Leading zeros are retained
+ try {
+ e = Entropy.fromString("000A");
+ if (e.cleanStr != "000A") {
+ return "Leading zeros are not retained";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Leading zeros are correctly preserved for hex in binary string
+ try {
+ e = Entropy.fromString("2A");
+ if (e.binaryStr != "00101010") {
+ return "Hex leading zeros are not correct in binary";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Leading zeros for base 6 as binary string
+ // 20 = 2 events at 2.58 bits per event = 5 bits
+ // 20 in base 6 = 12 in base 10 = 1100 in base 2
+ // so it needs 1 bit of padding to be the right bit length
+ try {
+ e = Entropy.fromString("20");
+ if (e.binaryStr != "01100") {
+ return "Base 6 as binary has leading zeros";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Leading zeros for base 10 as binary string
+ try {
+ e = Entropy.fromString("17");
+ if (e.binaryStr != "010001") {
+ return "Base 10 as binary has leading zeros";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Leading zeros for card entropy as binary string.
+ // Card entropy is hashed so 2c does not necessarily produce leading zeros.
+ try {
+ e = Entropy.fromString("2c");
+ if (e.binaryStr != "0010") {
+ return "Card entropy as binary has leading zeros";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Keyboard mashing results in weak entropy
+ // Despite being a long string, it's less than 30 bits of entropy
+ try {
+ e = Entropy.fromString("aj;se ifj; ask,dfv js;ifj");
+ if (e.binaryStr.length >= 30) {
+ return "Keyboard mashing should produce weak entropy";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Card entropy is used if every pair could be a card
+ try {
+ e = Entropy.fromString("4c3c2c");
+ if (e.base.str != "card") {
+ return "Card entropy not used if all pairs are cards";
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ // Card entropy uses base 52
+ // [ cards, binary ]
+ try {
+ var cards = [
+ [ "ac", "0101" ],
+ [ "acqs", "11011100" ],
+ [ "acks", "01011100" ],
+ [ "2cac", "11111000" ],
+ [ "2c", "0010" ],
+ [ "3d", "0001" ],
+ [ "4h", "1001" ],
+ [ "5s", "1001" ],
+ [ "6c", "0000" ],
+ [ "7d", "0001" ],
+ [ "8h", "1011" ],
+ [ "9s", "0010" ],
+ [ "tc", "1001" ],
+ [ "jd", "1111" ],
+ [ "qh", "0010" ],
+ [ "ks", "0101" ],
+ [ "ks2c", "01010100" ],
+ [ "KS2C", "01010100" ],
+ ];
+ for (var i=0; i<cards.length; i++) {
+ var card = cards[i][0];
+ var result = cards[i][1];
+ e = Entropy.fromString(card);
+ console.log(e.binary + " " + result);
+ if (e.binaryStr !== result) {
+ return "card entropy " + card + " not parsed correctly: " + result + " != " + e.binaryStr;
+ }
+ }
+ }
+ catch (e) {
+ return e.message;
+ }
+ return "PASS";
+ });
+ if (response != "PASS") {
+ console.log("Entropy unit tests");
+ console.log(response);
+ fail();
+ };
+ next();
+});
+},
+
+// Entropy can be entered by the user
+function() {
+page.open(url, function(status) {
+ expected = {
+ mnemonic: "abandon abandon ability",
+ address: "1Di3Vp7tBWtyQaDABLAjfWtF6V7hYKJtug",
+ }
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("00000000 00000000 00000000 00000000").trigger("input");
+ });
+ // check the mnemonic is set and address is correct
+ waitForGenerate(function() {
+ var actual = page.evaluate(function() {
+ return {
+ address: $(".address:first").text(),
+ mnemonic: $(".phrase").val(),
+ }
+ });
+ if (actual.mnemonic != expected.mnemonic) {
+ console.log("Entropy does not generate correct mnemonic");
+ console.log("Expected: " + expected.mnemonic);
+ console.log("Got: " + actual.mnemonic);
+ fail();
+ }
+ if (actual.address != expected.address) {
+ console.log("Entropy does not generate correct address");
+ console.log("Expected: " + expected.address);
+ console.log("Got: " + actual.address);
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// A warning about entropy is shown to the user, with additional information
+function() {
+page.open(url, function(status) {
+ // get text content from entropy sections of page
+ var hasWarning = page.evaluate(function() {
+ var entropyText = $(".entropy-container").text();
+ var warning = "mnemonic may be insecure";
+ if (entropyText.indexOf(warning) == -1) {
+ return false;
+ }
+ var readMoreText = $("#entropy-notes").parent().text();
+ var goodSources = "flipping a fair coin, rolling a fair dice, noise measurements etc";
+ if (readMoreText.indexOf(goodSources) == -1) {
+ return false;
+ }
+ return true;
+ });
+ // check the warnings and information are shown
+ if (!hasWarning) {
+ console.log("Page does not contain warning about using own entropy");
+ fail();
+ }
+ next();
+});
+},
+
+// The types of entropy available are described to the user
+function() {
+page.open(url, function(status) {
+ // get placeholder text for entropy field
+ var placeholder = page.evaluate(function() {
+ return $(".entropy").attr("placeholder");
+ });
+ var options = [
+ "binary",
+ "base 6",
+ "dice",
+ "base 10",
+ "hexadecimal",
+ "cards",
+ ];
+ for (var i=0; i<options.length; i++) {
+ var option = options[i];
+ if (placeholder.indexOf(option) == -1) {
+ console.log("Available entropy type is not shown to user: " + option);
+ fail();
+ }
+ }
+ next();
+});
+},
+
+// The actual entropy used is shown to the user
+function() {
+page.open(url, function(status) {
+ // use entropy
+ var badEntropySource = page.evaluate(function() {
+ var entropy = "Not A Very Good Entropy Source At All";
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val(entropy).trigger("input");
+ });
+ // check the actual entropy being used is shown
+ waitForEntropyFeedback(function() {
+ var expectedText = "AedEceAA";
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf(expectedText) == -1) {
+ console.log("Actual entropy used is not shown");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Binary entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("01").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("binary") == -1) {
+ console.log("Binary entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Base 6 entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("012345").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("base 6") == -1) {
+ console.log("Base 6 entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Base 6 dice entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("123456").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("dice") == -1) {
+ console.log("Dice entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Base 10 entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("789").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("base 10") == -1) {
+ console.log("Base 10 entropy is not detected and presented to user");
+ fail();
+ }
+ next();
+ });
+});
+},
+
+// Hexadecimal entropy can be entered
+function() {
+page.open(url, function(status) {
+ // use entropy
+ page.evaluate(function() {
+ $(".use-entropy").prop("checked", true).trigger("change");
+ $(".entropy").val("abcdef").trigger("input");
+ });
+ // check the entropy is shown to be the correct type
+ waitForEntropyFeedback(function() {
+ var entropyText = page.evaluate(function() {
+ return $(".entropy-container").text();
+ });
+ if (entropyText.indexOf("hexadecimal") == -1) {
+ console.log("Hexadecimal entropy is not detected and presented to user");
+ fail();