diff options
| -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 | ||||
| -rw-r--r-- | routes/sessions.js | 5 | ||||
| -rw-r--r-- | routes/users.js | 105 | ||||
| -rw-r--r-- | src/routes/sessions.coffee | 5 | ||||
| -rw-r--r-- | src/routes/users.coffee | 84 | ||||
| -rw-r--r-- | views/users/edit.html | 8 | ||||
| -rw-r--r-- | views/users/new.html | 11 |
12 files changed, 540 insertions, 141 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(-> diff --git a/routes/sessions.js b/routes/sessions.js index 38ae74b1..d01dc4f1 100644 --- a/routes/sessions.js +++ b/routes/sessions.js @@ -30,11 +30,12 @@ }); } return req.login(user, function(err) { - var url; + var re, url; if (err) { return next(err); } - if (req.session.redirect != null) { + re = new RegExp(user.username, 'g'); + if ((req.session.redirect != null) && re.test(req.session.redirect)) { url = req.session.redirect; } if (url == null) { diff --git a/routes/users.js b/routes/users.js index 1bffc7fb..47562df4 100644 --- a/routes/users.js +++ b/routes/users.js @@ -83,60 +83,63 @@ userkey = "user:" + req.body.username; return db.hgetall(userkey, function(err, obj) { if (obj) { - return res.redirect(req.body.username); - } else { - if (req.body.confirm !== req.body.password) { - errormsg += "Passwords must match"; - return res.render('users/new', { - layout: 'layout', - js: (function() { - return global.js; - }), - css: (function() { - return global.css; - }), - error: errormsg - }); - } - bcrypt.hash(req.body.password, 12, function(err, hash) { - db.sadd("users", userkey); - return db.hmset(userkey, { - username: req.body.username, - password: hash, - email: req.body.email - }, function() { - req.session.redirect = "/" + req.body.username + "/edit"; - return sessions.create(req, res); - }); + errormsg += "Username exists"; + } + if (req.body.confirm !== req.body.password) { + errormsg += "Passwords must match"; + } + if (errormsg) { + return res.render('users/new', { + layout: 'layout', + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }), + error: errormsg + }); + } + bcrypt.hash(req.body.password, 12, function(err, hash) { + db.sadd("users", userkey); + return db.hmset(userkey, { + username: req.body.username, + password: hash, + email: req.body.email, + pubkey: req.body.pubkey, + privkey: req.body.privkey + }, function() { + req.session.redirect = "/" + req.body.username + "/edit"; + return sessions.create(req, res); }); - return require('crypto').randomBytes(48, function(ex, buf) { - var token, url; - token = buf.toString('base64').replace(/\//g, '').replace(/\+/g, ''); - db.set(token, req.body.username); - url = "" + req.protocol + "://" + req.hostname + ":3000/verify/" + token; - return res.render('users/welcome', { - user: req.params.user, - layout: 'mail', - url: url, - js: (function() { - return global.js; - }), - css: (function() { - return global.css; - }) - }, function(err, html) { - var email, sendgrid; - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password); - email = new sendgrid.Email({ - to: req.body.email, - from: '[email protected]', - subject: 'Welcome to CoinOS', - html: html - }); - return sendgrid.send(email); + }); + return require('crypto').randomBytes(48, function(ex, buf) { + var token, url; + token = buf.toString('base64').replace(/\//g, '').replace(/\+/g, ''); + db.set(token, req.body.username); + url = "" + req.protocol + "://" + req.hostname + ":3000/verify/" + token; + return res.render('users/welcome', { + user: req.params.user, + layout: 'mail', + url: url, + js: (function() { + return global.js; + }), + css: (function() { + return global.css; + }) + }, function(err, html) { + var email, sendgrid; + sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password); + email = new sendgrid.Email({ + to: req.body.email, + from: '[email protected]', + subject: 'Welcome to CoinOS', + html: html }); + return sendgrid.send(email); }); - } + }); }); }, edit: function(req, res) { diff --git a/src/routes/sessions.coffee b/src/routes/sessions.coffee index 30d3cdef..5b1d9f06 100644 --- a/src/routes/sessions.coffee +++ b/src/routes/sessions.coffee @@ -21,7 +21,10 @@ module.exports = (passport) -> if (err) return next(err) - url = req.session.redirect if req.session.redirect? + re = new RegExp(user.username, 'g') + if req.session.redirect? and re.test(req.session.redirect) + url = req.session.redirect + url ?= "/#{user.username}" delete req.session.redirect return res.redirect(url) diff --git a/src/routes/users.coffee b/src/routes/users.coffee index 91654391..dc22303d 100644 --- a/src/routes/users.coffee +++ b/src/routes/users.coffee @@ -56,53 +56,57 @@ module.exports = (sessions) -> userkey = "user:"+req.body.username db.hgetall(userkey, (err, obj) -> if obj - res.redirect(req.body.username) - else - if req.body.confirm != req.body.password - errormsg += "Passwords must match" - return res.render('users/new', - layout: 'layout', - js: (-> global.js), - css: (-> global.css), - error: errormsg - ) + errormsg += "Username exists" - bcrypt.hash(req.body.password, 12, (err, hash) -> - db.sadd("users",userkey) - db.hmset(userkey, - username: req.body.username, - password: hash, - email: req.body.email - , -> - req.session.redirect = "/#{req.body.username}/edit" - sessions.create(req, res) - ) + if req.body.confirm != req.body.password + errormsg += "Passwords must match" + + if errormsg + return res.render('users/new', + layout: 'layout', + js: (-> global.js), + css: (-> global.css), + error: errormsg ) - require('crypto').randomBytes(48, (ex, buf) -> - token = buf.toString('base64').replace(/\//g,'').replace(/\+/g,'') - db.set(token, req.body.username) - url = "#{req.protocol}://#{req.hostname}:3000/verify/#{token}" + bcrypt.hash(req.body.password, 12, (err, hash) -> + db.sadd("users",userkey) + db.hmset(userkey, + username: req.body.username, + password: hash, + email: req.body.email, + pubkey: req.body.pubkey, + privkey: req.body.privkey + , -> + req.session.redirect = "/#{req.body.username}/edit" + sessions.create(req, res) + ) + ) + + require('crypto').randomBytes(48, (ex, buf) -> + token = buf.toString('base64').replace(/\//g,'').replace(/\+/g,'') + db.set(token, req.body.username) + url = "#{req.protocol}://#{req.hostname}:3000/verify/#{token}" - res.render('users/welcome', - user: req.params.user, - layout: 'mail', - url: url, - js: (-> global.js), - css: (-> global.css), - (err, html) -> - sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password) + res.render('users/welcome', + user: req.params.user, + layout: 'mail', + url: url, + js: (-> global.js), + css: (-> global.css), + (err, html) -> + sendgrid = require('sendgrid')(config.sendgrid_user, config.sendgrid_password) - email = new sendgrid.Email( - to: req.body.email - from: '[email protected]' - subject: 'Welcome to CoinOS' - html: html - ) + email = new sendgrid.Email( + to: req.body.email + from: '[email protected]' + subject: 'Welcome to CoinOS' + html: html + ) - sendgrid.send(email) - ) + sendgrid.send(email) ) + ) ) edit: (req, res) -> diff --git a/views/users/edit.html b/views/users/edit.html index a4ba131d..9307e52c 100644 --- a/views/users/edit.html +++ b/views/users/edit.html @@ -18,11 +18,11 @@ </div> <div class="form-group"> - <label for="bip32">Extended key:</label> + <label for="pubkey">Public Key:</label> <div class="input-group"> - <input type="text" id="bip32" name="bip32" class="form-control" placeholder="xpub..." /> + <input type="text" id="pubkey" name="pubkey" class="form-control" placeholder="xpub..." /> <span class="input-group-btn"> - <button id="generate" type="button" class="btn">Generate</button> + <button id="generate" type="button" class="btn">New</button> </span> </div> </div> @@ -40,7 +40,7 @@ </div> <div class="form-group"> - <label for="commission">Commission / Discount:</label> + <label for="commission">Commission (+) / Discount (-) %:</label> <input type="text" id="commission" name="commission" class="form-control" /> </div> diff --git a/views/users/new.html b/views/users/new.html index bf8b3b7d..ab3a9edd 100644 --- a/views/users/new.html +++ b/views/users/new.html @@ -20,14 +20,21 @@ </div> <div class="form-group"> - <label for="password">Password:</label> + <label for="password">Passphrase:</label> <input type="password" id="password" name="password" class="form-control" /> + <div id="messages"></div> </div> <div class="form-group"> - <label for="confirm">Confirm Password:</label> + <label for="confirm">Confirm Passphrase:</label> <input type="password" id="confirm" name="confirm" class="form-control" /> </div> + <input id="pubkey" name="pubkey" type="hidden" /> + <input id="privkey" name="privkey" type="hidden" /> + <input class="btn btn-primary" type="submit" value="Register" /> </form> + +<div id="qr"></div> + |
