diff options
| -rw-r--r-- | app.js | 2 | ||||
| -rw-r--r-- | config.js.sample | 4 | ||||
| -rw-r--r-- | package.json | 4 | ||||
| -rw-r--r-- | public/js/calculator.coffee | 5 | ||||
| -rw-r--r-- | routes/users.js | 56 | ||||
| -rw-r--r-- | src/app.coffee | 1 | ||||
| -rw-r--r-- | src/routes/users.coffee | 47 | ||||
| -rw-r--r-- | views/mail.html | 9 | ||||
| -rw-r--r-- | views/users/new.html | 12 | ||||
| -rw-r--r-- | views/users/show.html | 16 | ||||
| -rw-r--r-- | views/users/welcome.html | 7 |
11 files changed, 138 insertions, 25 deletions
@@ -121,6 +121,8 @@ app.post('/users', users.create); + app.get('/verify/:token', users.verify); + app.get('/:user/edit', authorize, users.edit); app.post('/:user', authorize, users.update); diff --git a/config.js.sample b/config.js.sample index 3d2d7a5c..db23257b 100644 --- a/config.js.sample +++ b/config.js.sample @@ -1,4 +1,8 @@ (function() { module.exports.secret = 'weareallmadeofstars'; + module.exports.sendgrid_user = 'user'; + + module.exports.sendgrid_password = 'password'; + }).call(this); diff --git a/package.json b/package.json index dd5d7a7b..343b76eb 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "passport": "0.2.0", "passport-local": "1.0.0", "redis": "0.11.0", - "request": "~2.40.0" + "request": "~2.40.0", + "nodemailer": "~1.2.1", + "sendgrid": "~1.2.0" }, "devDependencies": { "grunt": "^0.4.5", diff --git a/public/js/calculator.coffee b/public/js/calculator.coffee index c4b5f6d3..64a26a65 100644 --- a/public/js/calculator.coffee +++ b/public/js/calculator.coffee @@ -59,10 +59,7 @@ setup = -> else if g.user.title $('#title').html("<a href='/#{g.user.username}/edit'>#{g.user.title}</a>").show() - if g.user.bip32 - getAddress() - else - $('#bip32_notice').show() + getAddress() if g.user.bip32 $('#symbol').html(g.user.symbol + " bid") $('#currency').html(g.user.currency) diff --git a/routes/users.js b/routes/users.js index 2e94f027..31912c40 100644 --- a/routes/users.js +++ b/routes/users.js @@ -1,8 +1,10 @@ (function() { - var bcrypt, db; + var bcrypt, config, db; db = require("../redis"); + config = require("../config"); + bcrypt = require('bcrypt'); module.exports = function(sessions) { @@ -32,8 +34,9 @@ }, show: function(req, res) { return db.hgetall("user:" + req.params.user, function(err, obj) { + var options; if (obj) { - return res.render('users/show', { + options = { user: req.params.user, layout: 'layout', navigation: true, @@ -43,7 +46,12 @@ css: (function() { return global.css; }) - }); + }; + if (req.session.verified != null) { + options.verified = true; + } + res.render('users/show', options); + return delete req.session.verified; } else { return res.render('sessions/new', { notice: true, @@ -90,7 +98,7 @@ error: errormsg }); } - return bcrypt.hash(req.body.password, 12, function(err, hash) { + bcrypt.hash(req.body.password, 12, function(err, hash) { db.sadd("users", userkey); return db.hmset(userkey, { username: req.body.username, @@ -101,6 +109,33 @@ 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); + }); + }); } }); }, @@ -134,6 +169,19 @@ }); } }); + }, + verify: function(req, res) { + return db.get(req.params.token, function(err, reply) { + if (err || !reply) { + res.write('Invalid token'); + return res.end(); + } else { + return db.hset("user:" + (reply.toString()), "verified", "true", function() { + req.session.verified = true; + return res.redirect("/" + (reply.toString())); + }); + } + }); } }; }; diff --git a/src/app.coffee b/src/app.coffee index 986f3371..ae709fd0 100644 --- a/src/app.coffee +++ b/src/app.coffee @@ -73,6 +73,7 @@ app.get('/logout', sessions.destroy) app.get('/users/new', cache, users.new) app.post('/users', users.create) +app.get('/verify/:token', users.verify) app.get('/:user/edit', authorize, users.edit) app.post('/:user', authorize, users.update) diff --git a/src/routes/users.coffee b/src/routes/users.coffee index 26b28e1e..d2c88dc2 100644 --- a/src/routes/users.coffee +++ b/src/routes/users.coffee @@ -1,4 +1,5 @@ db = require("../redis") +config = require("../config") bcrypt = require('bcrypt') module.exports = (sessions) -> @@ -22,13 +23,18 @@ module.exports = (sessions) -> show: (req, res) -> db.hgetall("user:"+req.params.user, (err, obj) -> if obj - res.render('users/show', + options = user: req.params.user, layout: 'layout', navigation: true, js: (-> global.js), css: (-> global.css) - ) + + if req.session.verified? + options.verified = true + + res.render('users/show', options) + delete req.session.verified else res.render('sessions/new', notice: true, @@ -72,6 +78,31 @@ module.exports = (sessions) -> 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) + + email = new sendgrid.Email( + to: req.body.email + from: '[email protected]' + subject: 'Welcome to CoinOS' + html: html + ) + + sendgrid.send(email) + ) + ) ) edit: (req, res) -> @@ -96,3 +127,15 @@ module.exports = (sessions) -> ) ) ) + + verify: (req, res) -> + db.get(req.params.token, (err, reply) -> + if err or !reply + res.write('Invalid token') + res.end() + else + db.hset("user:#{reply.toString()}", "verified", "true", -> + req.session.verified = true + res.redirect("/#{reply.toString()}") + ) + ) diff --git a/views/mail.html b/views/mail.html new file mode 100644 index 00000000..ca91608a --- /dev/null +++ b/views/mail.html @@ -0,0 +1,9 @@ +<html> + <head> + <meta charset="utf-8" /> + <style> + body { font-family: "Helvetica Neue",Helvetica,Arial,sans-serif"; } + </style> + </head> + <body>{{{yield}}}</body> +</html> diff --git a/views/users/new.html b/views/users/new.html index fc9c5a21..bf8b3b7d 100644 --- a/views/users/new.html +++ b/views/users/new.html @@ -6,14 +6,20 @@ <form id="register" action="/users" method="post"> {{#error}} - <div class="alert alert-danger">{{error}}</div> + <div class="alert alert-danger">{{error}}</div> {{/error}} + <div class="form-group"> <label for="username">Username:</label> <input type="text" id="username" name="username" class="form-control" /> </div> <div class="form-group"> + <label for="email">Email:</label> + <input type="text" id="email" name="email" class="form-control" /> + </div> + + <div class="form-group"> <label for="password">Password:</label> <input type="password" id="password" name="password" class="form-control" /> </div> @@ -23,9 +29,5 @@ <input type="password" id="confirm" name="confirm" class="form-control" /> </div> - <div class="form-group"> - <label for="email">Email:</label> - <input type="text" id="email" name="email" class="form-control" /> - </div> <input class="btn btn-primary" type="submit" value="Register" /> </form> diff --git a/views/users/show.html b/views/users/show.html index e852f16a..2db57008 100644 --- a/views/users/show.html +++ b/views/users/show.html @@ -2,18 +2,16 @@ {{#js}}js/calculator{{/js}} {{/yield-scripts}} +{{#verified}} +<p class="alert alert-success alert-dismissible"> +<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button> +Your email has been verified. Thank you! +</p> +{{/verified}} + <div id="calculator" style="display: none"> <input id="user" type="hidden" value="{{user}}" /> - <div id="bip32_notice" class="panel panel-warning" style="display: none"> - <div class="panel-heading"> - <h3 class="panel-title">September 1, 2014</h3> - </div> - <div class="panel-body"> - We recently switched to using Bitcoin extended keys rather than single addresses to receive payments. Your account does not yet have an extended key associated with it. Please visit the <a href="/{{user}}/edit">Settings</a> page to create one now. - </div> - </div> - <h1 id="title"></h1> <a href="/{{user}}/edit"><img id="logo" src="/assets/img/bitcoin.png" alt="Logo" /></a> diff --git a/views/users/welcome.html b/views/users/welcome.html new file mode 100644 index 00000000..ad7cfac1 --- /dev/null +++ b/views/users/welcome.html @@ -0,0 +1,7 @@ +<div id="main-logo"></div> + +<h1>Welcome to CoinOS</h1> + +<p>Thanks for signing up! Please verify your email by clicking this link:<p> + +<div class="well"><a href="{{url}}">{{url}}</a></div> |
