aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2014-09-15 10:09:03 -0700
committerAdam Soltys <[email protected]>2014-09-15 10:09:03 -0700
commit0765adfc8993e8641e61a8db40965ef091c0f451 (patch)
tree3acbb32a40e47f295dec6b2085ef0f15213baaac
parentd07a4738359e1825e3629871b96c049275ab18c0 (diff)
downloadcoinos-server-0765adfc8993e8641e61a8db40965ef091c0f451.tar.gz
coinos-server-0765adfc8993e8641e61a8db40965ef091c0f451.zip
Mail key
-rw-r--r--public/js/calculator.coffee1
-rw-r--r--public/js/setup.coffee42
-rw-r--r--public/js/webqr.js2
-rw-r--r--routes/users.js38
-rw-r--r--src/routes/users.coffee30
-rw-r--r--util/migrate_address_to_pubkey.coffee13
-rw-r--r--views/calculator/sweep.html1
-rw-r--r--views/users/edit.html35
-rw-r--r--views/users/key.html7
-rw-r--r--views/users/welcome.html10
10 files changed, 133 insertions, 46 deletions
diff --git a/public/js/calculator.coffee b/public/js/calculator.coffee
index 14a25e6c..2032b9c3 100644
--- a/public/js/calculator.coffee
+++ b/public/js/calculator.coffee
@@ -52,6 +52,7 @@ setup = ->
g.tip = 1
g.user.address or= ''
g.user.commission or= 0
+ g.user.currency or= 'CAD'
g.user.symbol or= 'quadrigacx'
g.user.unit or= 'BTC'
diff --git a/public/js/setup.coffee b/public/js/setup.coffee
index deffcded..465cfb39 100644
--- a/public/js/setup.coffee
+++ b/public/js/setup.coffee
@@ -22,6 +22,8 @@ g = exports ? this
g.proceed = false
$(->
+ $('#encryption-password').pwstrength(showVerdicts: false)
+
$.getJSON("/js/rates.json", (data) ->
currencies = Object.keys(data)
currencies = currencies.sort()
@@ -51,6 +53,7 @@ $(->
user = $('#username').val()
$.getJSON("/#{user}.json", (data) ->
+ $('#email').val(data.email)
$('#title').val(data.title)
$('#logo').val(data.logo)
$('#pubkey').val(data.pubkey)
@@ -69,13 +72,6 @@ $(->
$('#unit').append("<option value='#{v}'>#{v}</option>")
)
- $('#title').blur(->
- if $(this).val() == '' and $('#logo').val() == ''
- $(this).parent().addClass('has-error')
- else
- $(this).parent().removeClass('has-error')
- )
-
$('#pubkey').blur(->
if check_address($(this).val())
$(this).parent().removeClass('has-error')
@@ -89,25 +85,23 @@ $(->
g.privkey = key.extended_private_key_string()
$('#modal').modal()
- $('#privkey').html(g.privkey)
+ $('#privkey_text').html(g.privkey)
$('#qr').html('')
new QRCode('qr', text: g.privkey, width: 260, height: 260)
)
$('#encryption-password').keyup((e) ->
return if e.keyCode is 9 or e.keyCode is 16
- enc_privkey = CryptoJS.AES.encrypt(g.privkey, $(this).val()).toString()
- enc_privkey = g.privkey if $(this).val() == ''
- $('#privkey').html(enc_privkey)
+ g.enc_privkey = CryptoJS.AES.encrypt(g.privkey, $(this).val()).toString()
+ g.enc_privkey = g.privkey if $(this).val() == ''
+ $('#privkey_text').html(g.enc_privkey)
$('#qr').html('')
- new QRCode('qr', text: enc_privkey, width: 260, height: 260)
+ new QRCode('qr', text: g.enc_privkey, width: 260, height: 260)
if $(this).val()
$('#status').html('(Encrypted)')
else
- $('#status').html('(Unencrypted Plaintext)')
-
-
+ $('#status').html('(Unencrypted)')
)
$('#confirm').blur(->
@@ -146,18 +140,26 @@ $(->
$('#close').click(->
$('#modal .form-control').blur()
if $('#modal .has-error').length > 0
+ $('#step1_link').click()
$('#modal .has-error').effect('shake', 500)
else
- g.update_pub_key = true
+ g.update_key = true
$('#modal').modal('hide')
)
+ $('#encrypt').submit(-> $('#close').click(); return false)
+
+ $('#modal').on('show.bs.modal', ->
+ $('#encryption-password, #encryption-confirm').val('').keyup().parent().removeClass('has-error')
+ $('#modal .alert').removeClass('alert-success').addClass('alert-danger')
+ )
$('#modal').on('shown.bs.modal', ->
- g.update_pub_key = false
- $('#encryption-password, #encryption-confirm').val('').blur()
- $('#encryption-password').pwstrength(showVerdicts: false)
+ g.update_key = false
+ $('#encryption-password').focus()
).on('hidden.bs.modal', ->
- $('#pubkey').val(g.pubkey) if g.update_pub_key
+ if g.update_key
+ $('#pubkey').val(g.pubkey)
+ $('#privkey').val(g.enc_privkey)
)
$('#setup').submit(->
diff --git a/public/js/webqr.js b/public/js/webqr.js
index ad80065d..18d4de4e 100644
--- a/public/js/webqr.js
+++ b/public/js/webqr.js
@@ -10,7 +10,7 @@ var webkit=false;
var moz=false;
var v=null;
-var vidhtml = '<video id="v" width="480" height="480" style="margin-top: -80px; padding: 0;" autoplay></video>';
+var vidhtml = '<video id="v" width="450" height="450" style="margin-top: -50px; padding: 0;" autoplay></video>';
$(function() {
load();
diff --git a/routes/users.js b/routes/users.js
index 47562df4..df89eb5b 100644
--- a/routes/users.js
+++ b/routes/users.js
@@ -114,14 +114,19 @@
});
});
return require('crypto').randomBytes(48, function(ex, buf) {
- var token, url;
+ var host, token, url;
token = buf.toString('base64').replace(/\//g, '').replace(/\+/g, '');
- db.set(token, req.body.username);
+ db.set("token:" + token, req.body.username);
+ host = req.hostname;
+ if (host === 'localhost') {
+ host += ':3000';
+ }
url = "" + req.protocol + "://" + req.hostname + ":3000/verify/" + token;
return res.render('users/welcome', {
user: req.params.user,
layout: 'mail',
url: url,
+ privkey: req.body.privkey,
js: (function() {
return global.js;
}),
@@ -172,7 +177,7 @@
if (req.body.password === '') {
delete req.body.password;
}
- return db.hmset("user:" + req.params.user, req.body, function() {
+ db.hmset("user:" + req.params.user, req.body, function() {
if (req.body.password != null) {
return bcrypt.hash(req.body.password, 12, function(err, hash) {
return db.hmset("user:" + req.params.user, {
@@ -185,11 +190,34 @@
return res.redirect("/" + req.params.user);
}
});
+ if ((req.body.privkey != null) && req.body.privkey !== '' && req.body.email !== '') {
+ return res.render('users/key', {
+ user: req.params.user,
+ layout: 'mail',
+ key: req.body.privkey,
+ 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: 'CoinOS Wallet Key',
+ html: html
+ });
+ return sendgrid.send(email);
+ });
+ }
},
verify: function(req, res) {
- return db.get(req.params.token, function(err, reply) {
+ return db.get("token:" + req.params.token, function(err, reply) {
if (err || !reply) {
- res.write('Invalid token');
+ res.write("Invalid Verification Token");
return res.end();
} else {
return db.hset("user:" + (reply.toString()), "verified", "true", function() {
diff --git a/src/routes/users.coffee b/src/routes/users.coffee
index dc22303d..e5a26af2 100644
--- a/src/routes/users.coffee
+++ b/src/routes/users.coffee
@@ -85,13 +85,16 @@ module.exports = (sessions) ->
require('crypto').randomBytes(48, (ex, buf) ->
token = buf.toString('base64').replace(/\//g,'').replace(/\+/g,'')
- db.set(token, req.body.username)
+ db.set("token:#{token}", req.body.username)
+ host = req.hostname
+ host += ':3000' if host is 'localhost'
url = "#{req.protocol}://#{req.hostname}:3000/verify/#{token}"
res.render('users/welcome',
user: req.params.user,
layout: 'mail',
url: url,
+ privkey: req.body.privkey,
js: (-> global.js),
css: (-> global.css),
(err, html) ->
@@ -130,6 +133,7 @@ module.exports = (sessions) ->
update: (req, res) ->
if req.body.password is ''
delete req.body.password
+
db.hmset("user:"+req.params.user, req.body, ->
if req.body.password?
bcrypt.hash(req.body.password, 12, (err, hash) ->
@@ -141,10 +145,30 @@ module.exports = (sessions) ->
res.redirect("/#{req.params.user}")
)
+ if req.body.privkey? and req.body.privkey != '' and req.body.email != ''
+ res.render('users/key',
+ user: req.params.user,
+ layout: 'mail',
+ key: req.body.privkey,
+ 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: 'CoinOS Wallet Key'
+ html: html
+ )
+
+ sendgrid.send(email)
+ )
+
verify: (req, res) ->
- db.get(req.params.token, (err, reply) ->
+ db.get("token:#{req.params.token}", (err, reply) ->
if err or !reply
- res.write('Invalid token')
+ res.write("Invalid Verification Token")
res.end()
else
db.hset("user:#{reply.toString()}", "verified", "true", ->
diff --git a/util/migrate_address_to_pubkey.coffee b/util/migrate_address_to_pubkey.coffee
new file mode 100644
index 00000000..8c2c43ac
--- /dev/null
+++ b/util/migrate_address_to_pubkey.coffee
@@ -0,0 +1,13 @@
+db = require('../redis')
+
+db.keys('user:*', (err, obj) ->
+ for user, i in obj
+ do (user) ->
+ db.hgetall(user, (err, obj) ->
+ console.log('Updating ' + user.toString())
+ if obj.bip32?
+ db.hset(user, 'pubkey', obj.bip32, ->)
+ else
+ db.hset(user, 'pubkey', obj.address, ->)
+ )
+)
diff --git a/views/calculator/sweep.html b/views/calculator/sweep.html
index 4a0ee3ee..92be828c 100644
--- a/views/calculator/sweep.html
+++ b/views/calculator/sweep.html
@@ -2,7 +2,6 @@
<script src='/js/jquery-1.8.2.min.js'></script>
<script src='/js/llqrcode.js'></script>
<script src='/js/webqr.js'></script>
-<script src='/js/socket.io.js'></script>
<script src='/js/bitcoinjs-min.js'></script>
<script src='/js/sweep.js'></script>
{{/yield-scripts}}
diff --git a/views/users/edit.html b/views/users/edit.html
index 66251923..0e0af3df 100644
--- a/views/users/edit.html
+++ b/views/users/edit.html
@@ -6,6 +6,7 @@
<h1>Settings</h1>
<input type="hidden" id="username" name="username" value="{{user}}" />
+ <input type="hidden" id="email" name="email" />
<div class="form-group">
<label for="title">Store Name:</label>
@@ -18,9 +19,10 @@
</div>
<div class="form-group">
- <label for="pubkey">Public Key:</label>
+ <label for="pubkey">Bitcoin Public Key:</label>
<div class="input-group">
<input type="text" id="pubkey" name="pubkey" class="form-control" placeholder="xpub..." />
+ <input type="hidden" id="privkey" name="privkey" />
<span class="input-group-btn">
<button id="generate" type="button" class="btn">New</button>
</span>
@@ -63,32 +65,37 @@
<div class="modal-body">
<ul class="nav nav-tabs" role="tablist">
- <li class="active"><a href="#step1" role="tab" data-toggle="tab">Key</a></li>
+ <li class="active"><a id="step1_link" href="#step1" role="tab" data-toggle="tab">Key</a></li>
<li><a href="#step2" role="tab" data-toggle="tab">What's this?</a></li>
</ul>
<div class="tab-content">
<div id="step1" class="tab-pane active">
- <div class="form-group">
- <label for="encryption-password">Encryption Password:</label>
- <input type="password" id="encryption-password" name="encryption-password" class="form-control" />
- </div>
+ <form id="encrypt">
+ <div class="form-group">
+ <label for="encryption-password">Encryption Password:</label>
+ <input type="password" id="encryption-password" name="encryption-password" class="form-control" />
+ </div>
- <div class="form-group">
- <label for="encryption-confirm">Confirm Password:</label>
- <input type="password" id="encryption-confirm" name="encryption-confirm" class="form-control" />
- </div>
+ <div class="form-group">
+ <label for="encryption-confirm">Confirm Password:</label>
+ <input type="password" id="encryption-confirm" name="encryption-confirm" class="form-control" />
+ </div>
+
+ <input type="submit" style="position: absolute; left: -9999px" />
+ </form>
<div id="key-dialog" class="alert alert-danger">
Extended Private Key <span id="status">(Unencrypted)</span>
- <pre id="privkey"></pre>
+ <pre id="privkey_text"></pre>
<div id="qr"></div>
</div>
</div>
<div id="step2" class="tab-pane">
- <p>This is an extended key, or <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki"><abbr title="Hierarchical Deterministic Wallet">HD Wallet</abbr></a>.</p>
+ <p>This is a Bitcoin extended key, also known as an <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki"><abbr title="Hierarchical Deterministic Wallet">HD Wallet</abbr></a>.</p>
<p>The <b>public</b> portion of the key is stored and used by CoinOS to generate a separate receiving address for every payment to your account. This prevents people from seeing transactions to your account other than their own.</p>
- <p>The <b>private</b> portion of the key currently displayed in the 'Key' tab will not be accessible after you close this window. You are responsible for saving it and making copies of it.</p>
- <p>Encrypting the key with a strong password prevents people from using the key if they get ahold of one of your copies. Keep the password written down and backed up separately from the key itself. <span class="text-danger"><b>We cannot reset your password</b> -- if you lose it or forget it, your funds will be lost forever.</span></p>
+ <p>The <b>private</b> portion of the key (displayed on the 'Key' tab) will not be accessible after you close this window. You are responsible for safely storing it and making copies of it, either by printing it out or saving it somewhere on your computer or online.</p>
+ <p>Encrypting the key with a strong password provides a safeguard against someone gaining access to a copy of the key. They will need to know your password to decrypt the key. Keep the password written down and backed up separately from the key.</p>
+ <p class="text-danger"><b>IMPORTANT: We cannot reset your password. If you lose it or forget it, any funds sent to your account will be lost forever.</b></p>
<img src="/assets/img/forever.gif" width="370px" />
</div>
diff --git a/views/users/key.html b/views/users/key.html
new file mode 100644
index 00000000..16388251
--- /dev/null
+++ b/views/users/key.html
@@ -0,0 +1,7 @@
+<h1>CoinOS Wallet Key</h1>
+
+<p>This is your wallet key, encrypted with the password you provided:</p>
+
+<pre>{{key}}</pre>
+
+<p>You will need this key, along with your password, to access funds that you receive. We can't recover your password for you if you forget it, so keep it written down somewhere safe.</p>
diff --git a/views/users/welcome.html b/views/users/welcome.html
index ad7cfac1..00c67ebd 100644
--- a/views/users/welcome.html
+++ b/views/users/welcome.html
@@ -1,7 +1,13 @@
-<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>
+
+<h2>Your Bitcoin Wallet</h2>
+
+<p>We've generated a Bitcoin wallet key for you to receive payments to. This is your private key, encrypted with your account password:</p>
+
+<pre>{{privkey}}</pre>
+
+<p>You will need this key, along with your password, to access funds that you receive. We can't recover your password for you if you forget it, so keep it written down somewhere safe.</p>