diff --git a/lib/db.js b/lib/db.js index 27826a0fb19433ea778668a42fbf9fdb08216add..379ed49093416b71915d29fe8d2e9f1ff8069402 100644 --- a/lib/db.js +++ b/lib/db.js @@ -79,6 +79,7 @@ exports.onReady = function(f) { 'emailKnown', 'emailToUID', 'emailType', + 'emailIsVerified', 'emailsBelongToSameAccount', 'haveVerificationSecret', 'isStaged', diff --git a/lib/db/json.js b/lib/db/json.js index 739cc260389414431aa41dccd441d3e228154a7e..1d63f174c7aa106bc0428dc334ee725169a1bfc7 100644 --- a/lib/db/json.js +++ b/lib/db/json.js @@ -104,6 +104,15 @@ exports.emailKnown = function(email, cb) { process.nextTick(function() { cb(null, m.length > 0) }); }; +exports.emailIsVerified = function(email, cb) { + sync(); + var m = jsel.match(".emails ." + ESC(email), db.users); + process.nextTick(function() { + if (!m.length) cb("no such email"); + else cb(null, m[0].verified); + }); +}; + exports.emailType = function(email, cb) { sync(); var m = jsel.match(".emails ." + ESC(email), db.users); diff --git a/lib/db/mysql.js b/lib/db/mysql.js index 18df02d44c474605e138bb52e26ab49e4807abdd..263620ed5bef4a6084ec148acb5db8daabeb3cbf 100644 --- a/lib/db/mysql.js +++ b/lib/db/mysql.js @@ -226,6 +226,17 @@ exports.emailType = function(email, cb) { ); } +exports.emailIsVerified = function(email, cb) { + client.query( + "SELECT verified FROM email WHERE address = ?", [ email ], + function(err, rows) { + if (rows && rows.length > 0) cb(err, !!rows[0].verified); + else cb('no such email'); + } + ); +}; + + exports.isStaged = function(email, cb) { client.query( "SELECT COUNT(*) as N FROM staged WHERE email = ?", [ email ], diff --git a/lib/wsapi/cert_key.js b/lib/wsapi/cert_key.js index 0f0c81ef3f8d7336db02f0ad90a6719fcc086957..0c0cb3e11f60da611d7224f4cb87a23a9bec75d0 100644 --- a/lib/wsapi/cert_key.js +++ b/lib/wsapi/cert_key.js @@ -21,18 +21,25 @@ exports.process = function(req, res) { db.userOwnsEmail(req.session.userid, req.body.email, function(err, owned) { if (err) return wsapi.databaseDown(res, err); - // not same account? big fat error - if (!owned) return httputils.badRequest(res, "that email does not belong to you"); + // not same account? big fat error + if (!owned) return httputils.badRequest(res, "that email does not belong to you"); - // forward to the keysigner! - var keysigner = urlparse(config.get('keysigner_url')); - keysigner.path = '/wsapi/cert_key'; - forward(keysigner, req, res, function(err) { - if (err) { - logger.error("error forwarding request to keysigner: " + err); - httputils.serverError(res, "can't contact keysigner"); - return; - } + // secondary addresses in the database may be "unverified". this occurs when + // a user forgets their password. We will not issue certs for unverified email + // addresses + db.emailIsVerified(req.body.email, function(err, verified) { + if (!verified) return httputils.forbidden(res, "that email requires (re)verification"); + + // forward to the keysigner! + var keysigner = urlparse(config.get('keysigner_url')); + keysigner.path = '/wsapi/cert_key'; + forward(keysigner, req, res, function(err) { + if (err) { + logger.error("error forwarding request to keysigner: " + err); + httputils.serverError(res, "can't contact keysigner"); + return; + } + }); }); }); }; diff --git a/tests/forgotten-pass-test.js b/tests/forgotten-pass-test.js index f9f97bb317b7a27fd8b0d8ee434a6449d5a83975..a4342dea913514511fc8246e035a83232e1b5e52 100755 --- a/tests/forgotten-pass-test.js +++ b/tests/forgotten-pass-test.js @@ -338,8 +338,7 @@ suite.addBatch({ }).call(this); }, "is forbidden" : function(err, r) { - assert.strictEqual(r.code, 401); - assert.strictEqual(JSON.parse(r.body).success, false); + assert.strictEqual(r.code, 403); } } }