aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app.js2
-rw-r--r--config.js.sample4
-rw-r--r--package.json4
-rw-r--r--public/js/calculator.coffee5
-rw-r--r--routes/users.js56
-rw-r--r--src/app.coffee1
-rw-r--r--src/routes/users.coffee47
-rw-r--r--views/mail.html9
-rw-r--r--views/users/new.html12
-rw-r--r--views/users/show.html16
-rw-r--r--views/users/welcome.html7
11 files changed, 138 insertions, 25 deletions
diff --git a/app.js b/app.js
index 9e5c3fed..04c8253a 100644
--- a/app.js
+++ b/app.js
@@ -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,
+ 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
+ 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">&times;</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>