diff options
| author | Adam Soltys <[email protected]> | 2014-09-06 19:40:55 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2014-09-06 19:40:55 -0700 |
| commit | e547723b23ccc58c832cac966b1b666a426afefb (patch) | |
| tree | 757da6f03a771c612002300e60e2adf60c2f98d8 /public | |
| parent | 86d321130850e15b580c1d4705fc0bdd9473f7d8 (diff) | |
| download | coinos-server-e547723b23ccc58c832cac966b1b666a426afefb.tar.gz coinos-server-e547723b23ccc58c832cac966b1b666a426afefb.zip | |
Generate key on registration
Diffstat (limited to 'public')
| -rw-r--r-- | public/css/calculator.less | 13 | ||||
| -rw-r--r-- | public/js/calculator.coffee | 4 | ||||
| -rw-r--r-- | public/js/check_password.js | 343 | ||||
| -rw-r--r-- | public/js/key.coffee | 28 | ||||
| -rw-r--r-- | public/js/register.coffee | 31 | ||||
| -rw-r--r-- | public/js/setup.coffee | 44 |
6 files changed, 422 insertions, 41 deletions
diff --git a/public/css/calculator.less b/public/css/calculator.less index 2764332b..10d4570d 100644 --- a/public/css/calculator.less +++ b/public/css/calculator.less @@ -71,3 +71,16 @@ td#total { font-weight: bold; text-align: right; } @page { margin: 0; } + +div.pass-container { + height: 30px; +} + +div.pass-bar { + height: 11px; + margin-top: 2px; +} +div.pass-hint { + font-family: arial; + font-size: 11px; +} diff --git a/public/js/calculator.coffee b/public/js/calculator.coffee index edbd4fa9..b31d3ee8 100644 --- a/public/js/calculator.coffee +++ b/public/js/calculator.coffee @@ -60,7 +60,7 @@ setup = -> if g.user.logo $('#logo').attr('src', g.user.logo).show() - getAddress() if g.user.bip32 + getAddress() if g.user.pubkey $('#symbol').html(g.user.currency) $('#currency').html(g.user.currency) @@ -196,7 +196,7 @@ logTransaction = (txid, amount) -> getAddress = -> i = g.user.index - bip32 = new BIP32(g.user.bip32) + bip32 = new BIP32(g.user.pubkey) result = bip32.derive("m/0/#{i}") hash160 = result.eckey.pubKeyHash g.user.address = (new Bitcoin.Address(hash160)).toString() diff --git a/public/js/check_password.js b/public/js/check_password.js new file mode 100644 index 00000000..f8fc40cc --- /dev/null +++ b/public/js/check_password.js @@ -0,0 +1,343 @@ +/* + jQuery(document).ready(function () { + "use strict"; + var $password = $(':password').pwstrength(), + common_words = ["password", "god", "123456"]; + + $password.pwstrength("addRule", "notEmail", function (options, word, score) { + return word.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i) && score; + }, -100, true); + + $password.pwstrength("addRule", "commonWords", function (options, word, score) { + var result = false; + $.each(common_words, function (i, item) { + var re = new RegExp(item, "gi"); + if (word.match(re)) { + result = score; + } + }); + return result; + }, -500, true); + }); + + */ + + + + +/*jslint vars: false, browser: true, nomen: true, regexp: true */ +/*global jQuery */ + +/* +* jQuery Password Strength plugin for Twitter Bootstrap +* +* Copyright (c) 2008-2013 Tane Piper +* Copyright (c) 2013 Alejandro Blanco +* Dual licensed under the MIT and GPL licenses. +* +*/ + +(function ($) { + "use strict"; + + var options = { + errors: [], + // Options + minChar: 8, + errorMessages: { + password_to_short: "The Password is too short", + same_as_username: "Your password cannot be the same as your username" + }, + scores: [17, 26, 40, 50], + verdicts: ["Weak", "Normal", "Medium", "Strong", "Very Strong"], + showVerdicts: true, + raisePower: 1.4, + usernameField: "#username", + onLoad: undefined, + onKeyUp: undefined, + viewports: { + progress: undefined, + verdict: undefined, + errors: undefined + }, + // Rules stuff + ruleScores: { + wordNotEmail: -100, + wordLength: -100, + wordSimilarToUsername: -100, + wordLowercase: 1, + wordUppercase: 3, + wordOneNumber: 3, + wordThreeNumbers: 5, + wordOneSpecialChar: 3, + wordTwoSpecialChar: 5, + wordUpperLowerCombo: 2, + wordLetterNumberCombo: 2, + wordLetterNumberCharCombo: 2 + }, + rules: { + wordNotEmail: true, + wordLength: true, + wordSimilarToUsername: true, + wordLowercase: true, + wordUppercase: true, + wordOneNumber: true, + wordThreeNumbers: true, + wordOneSpecialChar: true, + wordTwoSpecialChar: true, + wordUpperLowerCombo: true, + wordLetterNumberCombo: true, + wordLetterNumberCharCombo: true + }, + validationRules: { + wordNotEmail: function (options, word, score) { + return word.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i) && score; + }, + wordLength: function (options, word, score) { + var wordlen = word.length, + lenScore = Math.pow(wordlen, options.raisePower); + if (wordlen < options.minChar) { + lenScore = (lenScore + score); + options.errors.push(options.errorMessages.password_to_short); + } + return lenScore; + }, + wordSimilarToUsername: function (options, word, score) { + var username = $(options.usernameField).val(); + if (username && word.toLowerCase().match(username.toLowerCase())) { + options.errors.push(options.errorMessages.same_as_username); + return score; + } + return true; + }, + wordLowercase: function (options, word, score) { + return word.match(/[a-z]/) && score; + }, + wordUppercase: function (options, word, score) { + return word.match(/[A-Z]/) && score; + }, + wordOneNumber : function (options, word, score) { + return word.match(/\d+/) && score; + }, + wordThreeNumbers : function (options, word, score) { + return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score; + }, + wordOneSpecialChar : function (options, word, score) { + return word.match(/.[!,@,#,$,%,\^,&,*,?,_,~]/) && score; + }, + wordTwoSpecialChar : function (options, word, score) { + return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score; + }, + wordUpperLowerCombo : function (options, word, score) { + return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score; + }, + wordLetterNumberCombo : function (options, word, score) { + return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score; + }, + wordLetterNumberCharCombo : function (options, word, score) { + return word.match(/([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && score; + } + } + }, + + setProgressBar = function ($el, score) { + var options = $el.data("pwstrength"), + progressbar = options.progressbar.find('.progress-bar'), + $verdict; + + if (options.showVerdicts) { + if (options.viewports.verdict) { + $verdict = $(options.viewports.verdict).find(".password-verdict"); + } else { + $verdict = $el.parent().find(".password-verdict"); + if ($verdict.length === 0) { + $verdict = $('<span class="password-verdict"></span>'); + $verdict.insertAfter($el); + } + } + } + + + if (score < options.scores[0]) { + progressbar.addClass("progress-bar-danger").removeClass("progress-bar-warning").removeClass("progress-bar-success"); + progressbar.css("width", "5%"); + if (options.showVerdicts) { + $verdict.text(options.verdicts[0]); + } + } else if (score >= options.scores[0] && score < options.scores[1]) { + progressbar.addClass("progress-bar-danger").removeClass("progress-bar-warning").removeClass("progress-bar-success"); + progressbar.css("width", "25%"); + if (options.showVerdicts) { + $verdict.text(options.verdicts[1]); + } + } else if (score >= options.scores[1] && score < options.scores[2]) { + progressbar.addClass("progress-bar-warning").removeClass("progress-bar-danger").removeClass("progress-bar-success"); + progressbar.css("width", "50%"); + if (options.showVerdicts) { + $verdict.text(options.verdicts[2]); + } + } else if (score >= options.scores[2] && score < options.scores[3]) { + progressbar.addClass("progress-bar-warning").removeClass("progress-bar-danger").removeClass("progress-bar-success"); + progressbar.css("width", "75%"); + if (options.showVerdicts) { + $verdict.text(options.verdicts[3]); + } + } else if (score >= options.scores[3]) { + progressbar.addClass("progress-bar-success").removeClass("progress-bar-warning").removeClass("progress-bar-danger"); + progressbar.css("width", "100%"); + if (options.showVerdicts) { + $verdict.text(options.verdicts[4]); + } + } + }, + + calculateScore = function ($el) { + var self = this, + word = $el.val(), + totalScore = 0, + options = $el.data("pwstrength"); + + $.each(options.rules, function (rule, active) { + if (active === true) { + var score = options.ruleScores[rule], + result = options.validationRules[rule](options, word, score); + if (result) { + totalScore += result; + } + } + }); + setProgressBar($el, totalScore); + return totalScore; + }, + + progressWidget = function () { + return '<div class="progress"><div class="progress-bar progress-bar-striped"></div></div>'; + }, + + methods = { + init: function (settings) { + var self = this, + allOptions = $.extend(options, settings); + + return this.each(function (idx, el) { + var $el = $(el), + progressbar, + verdict; + + $el.data("pwstrength", allOptions); + + $el.on("keyup", function (event) { + var options = $el.data("pwstrength"); + options.errors = []; + calculateScore.call(self, $el); + if ($.isFunction(options.onKeyUp)) { + options.onKeyUp(event); + } + }); + + progressbar = $(progressWidget()); + if (allOptions.viewports.progress) { + $(allOptions.viewports.progress).append(progressbar); + } else { + progressbar.insertAfter($el); + } + progressbar.find(".bar").css("width", "0%"); + $el.data("pwstrength").progressbar = progressbar; + + if (allOptions.showVerdicts) { + verdict = $('<span class="password-verdict">' + allOptions.verdicts[0] + '</span>'); + if (allOptions.viewports.verdict) { + $(allOptions.viewports.verdict).append(verdict); + } else { + verdict.insertAfter($el); + } + } + + if ($.isFunction(allOptions.onLoad)) { + allOptions.onLoad(); + } + }); + }, + + destroy: function () { + this.each(function (idx, el) { + var $el = $(el); + $el.parent().find("span.password-verdict").remove(); + $el.parent().find("div.progress").remove(); + $el.parent().find("ul.error-list").remove(); + $el.removeData("pwstrength"); + }); + }, + + forceUpdate: function () { + var self = this; + this.each(function (idx, el) { + var $el = $(el), + options = $el.data("pwstrength"); + options.errors = []; + calculateScore.call(self, $el); + }); + }, + + outputErrorList: function () { + this.each(function (idx, el) { + var output = '<ul class="error-list">', + $el = $(el), + errors = $el.data("pwstrength").errors, + viewports = $el.data("pwstrength").viewports, + verdict; + $el.parent().find("ul.error-list").remove(); + + if (errors.length > 0) { + $.each(errors, function (i, item) { + output += '<li>' + item + '</li>'; + }); + output += '</ul>'; + if (viewports.errors) { + $(viewports.errors).html(output); + } else { + output = $(output); + verdict = $el.parent().find("span.password-verdict"); + if (verdict.length > 0) { + el = verdict; + } + output.insertAfter(el); + } + } + }); + }, + + addRule: function (name, method, score, active) { + this.each(function (idx, el) { + var options = $(el).data("pwstrength"); + options.rules[name] = active; + options.ruleScores[name] = score; + options.validationRules[name] = method; + }); + }, + + changeScore: function (rule, score) { + this.each(function (idx, el) { + $(el).data("pwstrength").ruleScores[rule] = score; + }); + }, + + ruleActive: function (rule, active) { + this.each(function (idx, el) { + $(el).data("pwstrength").rules[rule] = active; + }); + } + }; + + $.fn.pwstrength = function (method) { + var result; + if (methods[method]) { + result = methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === "object" || !method) { + result = methods.init.apply(this, arguments); + } else { + $.error("Method " + method + " does not exist on jQuery.pwstrength"); + } + return result; + }; +}(jQuery)); diff --git a/public/js/key.coffee b/public/js/key.coffee new file mode 100644 index 00000000..f964b0cf --- /dev/null +++ b/public/js/key.coffee @@ -0,0 +1,28 @@ +Key = -> + rng = new SecureRandom() + bytes = new Array(256) + rng.nextBytes(bytes) + + hasher = new jsSHA(bytes.toString(), 'TEXT') + rng.nextBytes(bytes) + + I = hasher.getHMAC(bytes.toString(), "TEXT", "SHA-512", "HEX") + il = Crypto.util.hexToBytes(I.slice(0, 64)) + ir = Crypto.util.hexToBytes(I.slice(64, 128)) + + key = new BIP32() + key.eckey = new Bitcoin.ECKey(il) + key.eckey.pub = key.eckey.getPubPoint() + key.eckey.setCompressed(true) + key.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(key.eckey.pub.getEncoded(true)) + key.has_private_key = true + + key.chain_code = ir + key.child_index = 0 + key.parent_fingerprint = Bitcoin.Util.hexToBytes("00000000") + key.version = BITCOIN_MAINNET_PRIVATE + key.depth = 0 + + key.build_extended_public_key() + key.build_extended_private_key() + return key diff --git a/public/js/register.coffee b/public/js/register.coffee index 342cbea3..0e47a794 100644 --- a/public/js/register.coffee +++ b/public/js/register.coffee @@ -1,10 +1,35 @@ #= require js/jquery-1.8.2.min.js #= require js/jquery-ui.min.js -#= require js/score_password.js #= require js/check_email.js +#= require js/check_password.js +#= require js/jsbn.js +#= require js/jsbn2.js +#= require js/crypto-min.js +#= require js/2.5.3-crypto-sha256.js +#= require js/sha512.js +#= require js/rfc1751.js +#= require js/bitcoinjs-min.js +#= require js/modsqrt.js +#= require js/bip32.js +#= require js/secure_random.js +#= require js/key.js +#= require js/aes.js +g = this $(-> $('#username').focus() + $('#password').pwstrength(showVerdicts: false) + + key = new Key() + $('#pubkey').val(key.extended_public_key_string()) + privkey = key.extended_private_key_string() + + $('#password').keyup((e) -> + return if e.keyCode is 9 or e.keyCode is 16 + enc_privkey = CryptoJS.AES.encrypt(privkey, $(this).val()).toString() + enc_privkey = privkey if $(this).val() == '' + $('#privkey').val(enc_privkey) + ) $('#username').blur(-> $(this).parent().next('.alert').remove() @@ -19,13 +44,11 @@ $(-> $('#password').blur(-> $('#confirm').blur() $(this).parent().next('.alert').remove() - score = scorePassword($(this).val()) - if score > 40 + if $('.progress-bar-success').length > 0 $(this).parent().removeClass('has-error') else $(this).parent().addClass('has-error') - $(this).parent().after('<div class="alert alert-danger">Weak password</div>') ) $('#confirm').blur(-> diff --git a/public/js/setup.coffee b/public/js/setup.coffee index 272e2159..8348aaf4 100644 --- a/public/js/setup.coffee +++ b/public/js/setup.coffee @@ -2,19 +2,19 @@ #= require ../js/jquery-ui.min.js #= require ../js/jquery.printElement.min.js #= require ../js/bootstrap.min.js -#= require ../js/crypto-min.js -#= require ../js/2.5.3-crypto-sha256.js #= require ../js/jsbn.js #= require ../js/jsbn2.js -#= require ../js/check_address.js -#= require ../js/bitcoinjs-min.js +#= require ../js/crypto-min.js +#= require ../js/2.5.3-crypto-sha256.js #= require ../js/sha512.js -#= require ../js/modsqrt.js #= require ../js/rfc1751.js +#= require ../js/bitcoinjs-min.js +#= require ../js/modsqrt.js #= require ../js/bip32.js #= require ../js/secure_random.js #= require ../js/qrcode.js #= require ../js/aes.js +#= require ../js/key.js g = exports ? this g.proceed = false @@ -51,7 +51,7 @@ $(-> $.getJSON("/#{user}.json", (data) -> $('#title').val(data.title) $('#logo').val(data.logo) - $('#bip32').val(data.bip32) + $('#pubkey').val(data.pubkey) $('#address').val(data.address) $("#symbol option[value='#{data.symbol}']").attr('selected', 'selected') $('#commission').val(data.commission) @@ -74,7 +74,7 @@ $(-> $(this).parent().removeClass('has-error') ) - $('#bip32').blur(-> + $('#pubkey').blur(-> try new BIP32($(this).val()) $(this).parent().removeClass('has-error') @@ -83,33 +83,7 @@ $(-> ) $('#generate').click(-> - rng = new SecureRandom() - bytes = new Array(256) - rng.nextBytes(bytes) - - hasher = new jsSHA(bytes.toString(), 'TEXT') - rng.nextBytes(bytes) - - I = hasher.getHMAC(bytes.toString(), "TEXT", "SHA-512", "HEX") - il = Crypto.util.hexToBytes(I.slice(0, 64)) - ir = Crypto.util.hexToBytes(I.slice(64, 128)) - - key = new BIP32() - key.eckey = new Bitcoin.ECKey(il) - key.eckey.pub = key.eckey.getPubPoint() - key.eckey.setCompressed(true) - key.eckey.pubKeyHash = Bitcoin.Util.sha256ripe160(key.eckey.pub.getEncoded(true)) - key.has_private_key = true - - key.chain_code = ir - key.child_index = 0 - key.parent_fingerprint = Bitcoin.Util.hexToBytes("00000000") - key.version = BITCOIN_MAINNET_PRIVATE - key.depth = 0 - - key.build_extended_public_key() - key.build_extended_private_key() - + key = new Key() g.pubkey = key.extended_public_key_string() g.privkey = key.extended_private_key_string() @@ -186,7 +160,7 @@ $(-> if $('.tab-pane:eq(2)').hasClass('active') $('a[data-toggle="tab"]:eq(1)').click() ).on('hidden.bs.modal', -> - $('#bip32').val(g.pubkey) if g.update_pub_key + $('#pubkey').val(g.pubkey) if g.update_pub_key ) $('#setup').submit(-> |
