diff --git a/browserid/app.js b/browserid/app.js index 3b1fbd49ab3fb8ad2062348a1319aaafc8dadd21..e116604c8b7f46b8b3567be21cbe8c43a2c6e773 100644 --- a/browserid/app.js +++ b/browserid/app.js @@ -1,16 +1,18 @@ -const path = require('path'), - url = require('url'), - fs = require('fs'), +const fs = require('fs'), + path = require('path'); + +// create the var directory if it doesn't exist +var VAR_DIR = path.join(__dirname, "var"); +try { fs.mkdirSync(VAR_DIR, 0755); } catch(e) { }; + +const url = require('url'), wsapi = require('./lib/wsapi.js'), httputils = require('./lib/httputils.js'), webfinger = require('./lib/webfinger.js'), sessions = require('cookie-sessions'), express = require('express'), - secrets = require('./lib/secrets.js'); - -// create the var directory if it doesn't exist -var VAR_DIR = path.join(__dirname, "var"); -try { fs.mkdirSync(VAR_DIR, 0755); } catch(e) { } + secrets = require('./lib/secrets.js'), + db = require('./lib/db.js'); const STATIC_DIR = path.join(path.dirname(__dirname), "static"); diff --git a/browserid/lib/db.js b/browserid/lib/db.js index 43ea98536b95bc7b4877805f190a123a4c74a7ab..e3aa128dc1ee7256291ea487d15698150ac01ac8 100644 --- a/browserid/lib/db.js +++ b/browserid/lib/db.js @@ -1,28 +1,40 @@ const sqlite = require('sqlite'), path = require('path'); +var VAR_DIR = path.join(path.dirname(__dirname), "var"); + var db = new sqlite.Database(); +var dbPath = path.join(VAR_DIR, "authdb.sqlite"); + +var ready = false; +var waiting = []; -db.open(path.join(path.dirname(__dirname), "var", "authdb.sqlite"), function (error) { +db.open(dbPath, function (error) { if (error) { console.log("Couldn't open database: " + error); throw error; } - - function createTable(name, sql) { - db.execute(sql, function (error, rows) { + db.executeScript( + "CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, password TEXT );" + + "CREATE TABLE IF NOT EXISTS emails ( id INTEGER PRIMARY KEY, user INTEGER, address TEXT UNIQUE );" + + "CREATE TABLE IF NOT EXISTS keys ( id INTEGER PRIMARY KEY, email INTEGER, key TEXT, expires INTEGER )", + function (error) { if (error) { - console.log("Couldn't create " + name + " table: " + error); throw error; } + ready = true; + waiting.forEach(function(f) { f() }); + waiting = []; }); - } - - createTable('users', "CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, password TEXT )"); - createTable('emails', "CREATE TABLE IF NOT EXISTS emails ( id INTEGER PRIMARY KEY, user INTEGER, address TEXT UNIQUE )"); - createTable('keys', "CREATE TABLE IF NOT EXISTS keys ( id INTEGER PRIMARY KEY, email INTEGER, key TEXT, expires INTEGER )"); }); +exports.onReady = function(f) { + setTimeout(function() { + if (ready) f(); + else waiting.push(f); + }, 0); +}; + // half created user accounts (pending email verification) // OR // half added emails (pending verification) @@ -105,15 +117,15 @@ exports.addEmailToAccount = function(existing_email, email, pubkey, cb) { if (userID == undefined) { cb("no such email: " + existing_email, undefined); } else { - executeTransaction([ - [ "INSERT INTO emails (user, address) VALUES(?,?)", [ userID, email ] ], - [ "INSERT INTO keys (email, key, expires) VALUES(last_insert_rowid(),?,?)", - [ pubkey, ((new Date()).getTime() + (14 * 24 * 60 * 60 * 1000)) ] - ] - ], function (error) { - if (error) cb(error); - else cb(); - }); + executeTransaction([ + [ "INSERT INTO emails (user, address) VALUES(?,?)", [ userID, email ] ], + [ "INSERT INTO keys (email, key, expires) VALUES(last_insert_rowid(),?,?)", + [ pubkey, ((new Date()).getTime() + (14 * 24 * 60 * 60 * 1000)) ] + ] + ], function (error) { + if (error) cb(error); + else cb(); + }); } }); } @@ -281,19 +293,18 @@ exports.pubkeysForEmail = function(identity, cb) { // FIXME: I'm not sure I'm using this data model properly exports.removeEmail = function(authenticated_email, email, cb) { - // figure out the user, and remove Email only from addressed - // linked to the authenticated email address - emailToUserID(authenticated_email, function(user_id) { - executeTransaction([ - [ "delete from emails where emails.address = ? and user = ?", [ email,user_id ] ] , - [ "delete from keys where email in (select address from emails where emails.address = ? and user = ?)", [ email,user_id ] ], - ], function (error) { - if (error) cb(error); - else cb(); - }); + // figure out the user, and remove Email only from addressed + // linked to the authenticated email address + emailToUserID(authenticated_email, function(user_id) { + executeTransaction([ + [ "delete from emails where emails.address = ? and user = ?", [ email,user_id ] ] , + [ "delete from keys where email in (select address from emails where emails.address = ? and user = ?)", [ email,user_id ] ], + ], function (error) { + if (error) cb(error); + else cb(); }); + }); }; - exports.cancelAccount = function(authenticated_email, cb) { emailToUserID(authenticated_email, function(user_id) { executeTransaction([ diff --git a/browserid/run.js b/browserid/run.js index 564a6afc37b1256792b15139ccba1b799a4b1e91..6e5697ba0e0123806d74fdb99a8a709da245c97c 100755 --- a/browserid/run.js +++ b/browserid/run.js @@ -1,24 +1,44 @@ #!/usr/bin/env node var path = require("path"), - fs = require("fs"), - express = require("express"); + fs = require("fs"), + express = require("express"); -var PRIMARY_HOST = "127.0.0.1"; -var PRIMARY_PORT = 62700; +const amMain = (process.argv[1] === __filename); + +const PRIMARY_HOST = "127.0.0.1"; +const PRIMARY_PORT = 62700; var handler = require("./app.js"); -var app = express.createServer(); +var app = undefined; + +exports.runServer = function() { + if (app) return; + + app = express.createServer(); -app.use(express.logger({ + app.use(express.logger({ stream: fs.createWriteStream(path.join(handler.varDir, "server.log")) -})); + })); + + // let the specific server interact directly with the connect server to register their middleware + if (handler.setup) handler.setup(app); + + // use the express 'static' middleware for serving of static files (cache headers, HTTP range, etc) + app.use(express.static(path.join(__dirname, "static"))); -// let the specific server interact directly with the connect server to register their middleware -if (handler.setup) handler.setup(app); + app.listen(PRIMARY_PORT, PRIMARY_HOST); +}; -// use the express 'static' middleware for serving of static files (cache headers, HTTP range, etc) -app.use(express.static(path.join(__dirname, "static"))); +exports.stopServer = function(cb) { + if (!app) return; + app.on('close', function() { + cb(); + }); + app.close(); + app = undefined; +} -app.listen(PRIMARY_PORT, PRIMARY_HOST); +// when directly invoked from the command line, we'll start the server +if (amMain) exports.runServer(); diff --git a/browserid/tests/forgotten-email-test.js b/browserid/tests/forgotten-email-test.js new file mode 100755 index 0000000000000000000000000000000000000000..dfc0f7e5e60c75b6be0625a620ffe1baa1ee1b94 --- /dev/null +++ b/browserid/tests/forgotten-email-test.js @@ -0,0 +1,42 @@ +#!/usr/bin/env node + +const assert = require('assert'), + vows = require('vows'), + fs = require('fs'), + path = require('path'); + +const amMain = (process.argv[1] === __filename); +const varPath = path.join(path.dirname(__dirname), "var"); + +function removeServerData() { + fs.readdirSync(varPath).forEach(function(f) { + fs.unlinkSync(path.join(varPath, f)); + }); +} + +// 10. remove the user database +removeServerData() + +// 20. run the server +require("../run.js").runServer(); + +// create a new account via the api with (first address) + +// manually verify the account + +// add a new email address to the account (second address) + +// run the "forgot_email" flow with first address + +// try to log into the first email address with oldpassword + +// try to log into the second email address with oldpassword + +// try to log into the first email with newpassword + + +// stop the server +require("../run.js").stopServer(); + +// clean up +removeServerData();