diff --git a/.gitignore b/.gitignore index a03c5e3933569d05747d2a3e1219fbce7da36a60..1823f2e5796b4df5d7c5694ff922d2e906b415a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *~ \#*\# .\#* -node_modules +/node_modules +/var diff --git a/ChangeLog b/ChangeLog index a2e7f3ae24920567d2acba932cb5f5ffa8888c8a..87040e9dfcabf257e202b9adcdf208d4c74836dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,2 +1,12 @@ +train-2011.08.04: + * when user closes dialog without clicking "cancel", properly return 'null' to the webpage (via getVerifiedEmail callback) - issue #107 + * improve checks to warn developer that prerequisite software is missing. issue #110 + * parameterize software to support multiple deployment environments (dev/beta/prod) issues #102 & #52 + * documentation updates. + * improved logging (using the winston logging framework for node.js) + * [website] fixed inclusion of youtube video (now over https to keep browsers from getting scared about mixed mode resource inclusion) + train-1: - * beginning of time, everything is new. + * beginning of time, everything is new. + * (2011.08.03) include youtube video embedding over https (issue #112) + * (2011.08.04) fix mozillalabs.com link in dialog (issue #116) diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index 54a350162cdea99ed069928217df0c21cf9814b7..36639c0b2461db12f0ddd7f25bb51f63254e929d 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -85,9 +85,17 @@ Subsequent steps use different software which you might need to install. * **curl** - used to iniate http requests from the cmd line (to kick the browserid server) * **java** - used to minify css - * **libsqlite3-dev** - database libraries + * **mysql 5.1+** - the preferred persistence backend -### 4. Set up post-update hook +### 4. Set up mysql + + 0. ensure you can connect via TCP - localhost:3306 (like, make sure skip-networking is off in my.cnf) + 1. connect to the database as user root + 2. `CREATE USER 'browserid'@'localhost' IDENTIFIED BY 'browserid';` + 3. `CREATE DATABASE browserid;` + 4. `GRANT CREATE, DELETE, INDEX, INSERT, LOCK TABLES, SELECT, UPDATE ON browserid.* TO 'browserid'@'localhost';` + +### 5. Set up post-update hook *This step is optional* - if you want to manually update code you probably skipped step #1, you can skip this one as well. All you need diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..173bdc47afb6bff9936d8c92f1742d4f21244261 --- /dev/null +++ b/LICENSE @@ -0,0 +1,5 @@ +This software is available under your choice of the following licenses: + + * MPL 1.1 or later: http://www.mozilla.org/MPL/ + * GPL 2.0 or later: http://www.gnu.org/licenses/gpl.html + * LGPL 2.1 or later: http://www.gnu.org/licenses/lgpl.html diff --git a/README.md b/README.md index e84edefb0d776fd66d4553e07bd87f77352498a3..518808162dd1ff1aad9c10ecd7bd72330778e21b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Here's the software you'll need installed: * node.js (>= 0.4.5): http://nodejs.org/ * npm: http://npmjs.org/ -* sqlite (3) development libraries: http://www.sqlite.org/ * Several node.js 3rd party libraries - see `package.json` for details ## Getting started: diff --git a/browserid/app.js b/browserid/app.js index c62b6a2d8ec9dc419cb9c7a3e7d0805825691083..2f020e2bcec9d7a07493cce35f927bd31a420c1e 100644 --- a/browserid/app.js +++ b/browserid/app.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const fs = require('fs'), path = require('path'); @@ -12,12 +47,17 @@ crypto = require('crypto'), wsapi = require('./lib/wsapi.js'), httputils = require('./lib/httputils.js'), webfinger = require('./lib/webfinger.js'), -sessions = require('cookie-sessions'), +//sessions = require('cookie-sessions'), +sessions = require('connect-cookie-session'), express = require('express'), secrets = require('./lib/secrets.js'), db = require('./lib/db.js'), configuration = require('../libs/configuration.js'), substitution = require('../libs/substitute.js'); +logging = require("../libs/logging.js"); + +// open the databse +db.open(configuration.get('database')); // looks unused, see run.js // const STATIC_DIR = path.join(path.dirname(__dirname), "static"); @@ -32,7 +72,7 @@ function internal_redirector(new_url) { } function router(app) { - app.set("views", __dirname + '/views'); + app.set("views", __dirname + '/views'); app.set('view options', { production: configuration.get('use_minified_resources') @@ -40,7 +80,8 @@ function router(app) { // this should probably be an internal redirect // as soon as relative paths are figured out. - app.get('/sign_in', function(req, res, next ){ + app.get('/sign_in', function(req, res, next ) { + logging.userEntry('browserid', req); res.render('dialog.ejs', { title: 'A Better Way to Sign In', layout: false, @@ -114,15 +155,31 @@ function router(app) { exports.varDir = VAR_DIR; exports.setup = function(server) { + // over SSL? + var overSSL = (configuration.get('scheme') == 'https'); + server.use(express.cookieParser()); var cookieSessionMiddleware = sessions({ secret: COOKIE_SECRET, - session_key: COOKIE_KEY, - path: '/' + // session_key: COOKIE_KEY, + key: COOKIE_KEY, + cookie: { + path: '/', + httpOnly: true, + maxAge: 14400000, + secure: overSSL + } }); + // cookie sessions server.use(function(req, resp, next) { + // we set this parameter so the connect-cookie-session + // sends the cookie even though the local connection is HTTP + // (the load balancer does SSL) + if (overSSL) + req.connection.proxySecure = true; + try { cookieSessionMiddleware(req, resp, next); } catch(e) { @@ -156,6 +213,15 @@ exports.setup = function(server) { next(); }); + // Strict Transport Security + server.use(function(req, resp, next) { + if (overSSL) { + // expires in 30 days, include subdomains like www + resp.setHeader("Strict-Transport-Security", "max-age=2592000; includeSubdomains"); + } + next(); + }); + // prevent framing server.use(function(req, resp, next) { resp.setHeader('x-frame-options', 'DENY'); diff --git a/browserid/lib/db.js b/browserid/lib/db.js index 482fad4c1d92afa2b94ae982959d540a6f880571..7baab9a6e27577257ee7b21dfa05e69c05098698 100644 --- a/browserid/lib/db.js +++ b/browserid/lib/db.js @@ -1,391 +1,111 @@ -const -sqlite = require('sqlite'), -path = require('path'); - -var VAR_DIR = path.join(path.dirname(__dirname), "var"); - -var db = new sqlite.Database(); - -// a configurable parameter if set immediately after require() of db.js -exports.dbPath = path.join(VAR_DIR, "authdb.sqlite"); +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var driver; var ready = false; var waiting = []; +function checkReady() { + if (!ready) throw "database not ready. did you call open()?"; +} + // async break allow database path to be configured by calling code // a touch tricky cause client must set dbPath before releasing // control of the runloop -setTimeout(function() { - db.open(exports.dbPath, function (error) { - if (error) { - console.log("Couldn't open database: " + error); - throw error; - } - 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) { - throw error; - } - ready = true; - waiting.forEach(function(f) { f() }); - waiting = []; - }); - }); -}, 0); - -// accepts a function that will be invoked once the database is ready for transactions. -// this hook is important to pause the rest of application startup until async database -// connection establishment is complete. -exports.onReady = function(f) { - setTimeout(function() { - if (ready) f(); - else waiting.push(f); - }, 0); -}; - -// XXX: g_staged and g_stagedEmails should be moved into persistent/fast storage. - -// half created user accounts (pending email verification) -// OR -// half added emails (pending verification) -var g_staged = { -}; - -// an email to secret map for efficient fulfillment of isStaged queries -var g_stagedEmails = { -}; - -function executeTransaction(statements, cb) { - function executeTransaction2(statements, cb) { - if (statements.length == 0) cb(); - else { - var s = statements.shift(); - db.execute(s[0], s[1], function(err, rows) { - if (err) cb(err); - else executeTransaction2(statements, cb); - }); - } +exports.open = function(cfg, cb) { + var driverName = "json"; + if (cfg && cfg.driver) driverName = cfg.driver; + try { + driver = require('./db_' + driverName + '.js'); + } catch(e) { + var msg = "FATAL: couldn't find database driver: " + driverName; + console.log(msg); + throw msg + ": " + e.toString(); } - db.execute('BEGIN', function(err, rows) { - executeTransaction2(statements, function(err) { - if (err) cb(err); - else db.execute('COMMIT', function(err, rows) { - cb(err); - }); - }); - }); -} - -function emailToUserID(email, cb) { - db.execute( - 'SELECT users.id FROM emails, users WHERE emails.address = ? AND users.id == emails.user', - [ email ], - function (err, rows) { - if (rows && rows.length == 1) { - cb(rows[0].id); - } else { - if (err) console.log("database error: " + err); - cb(undefined); + driver.open(cfg, function(error) { + if (error) { + if (cb) cb(error); + else { + console.log("ERROR:" + error); + process.exit(1); } - }); -} - -exports.emailKnown = function(email, cb) { - db.execute( - "SELECT id FROM emails WHERE address = ?", - [ email ], - function(error, rows) { - cb(rows.length > 0); - }); -}; - -// XXX: should be moved to async. -exports.isStaged = function(email) { - return g_stagedEmails.hasOwnProperty(email); -}; - -function generateSecret() { - var str = ""; - const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (var i=0; i < 48; i++) { - str += alphabet.charAt(Math.floor(Math.random() * alphabet.length)); - } - return str; -} - -function addEmailToAccount(existing_email, email, pubkey, cb) { - emailToUserID(existing_email, function(userID) { - 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(); - }); + ready = true; + waiting.forEach(function(f) { f() }); + waiting = []; + if (cb) cb(); } }); -} - -exports.emailsBelongToSameAccount = function(lhs, rhs, cb) { - emailToUserID(lhs, function(lhs_uid) { - emailToUserID(rhs, function(rhs_uid) { - cb(lhs_uid === rhs_uid); - }, function (error) { - cb(false); - }); - }, function (error) { - cb(false); - }); }; -exports.addKeyToEmail = function(existing_email, email, pubkey, cb) { - emailToUserID(existing_email, function(userID) { - if (userID == undefined) { - cb("no such email: " + existing_email, undefined); - return; - } - db.execute("SELECT emails.id FROM emails,users WHERE users.id = ? AND emails.address = ? AND emails.user = users.id", - [ userID, email ], - function(err, rows) { - if (err || rows.length != 1) { - cb(err); - return; - } - executeTransaction([ - [ "INSERT INTO keys (email, key, expires) VALUES(?,?,?)", - [ rows[0].id, pubkey, ((new Date()).getTime() + (14 * 24 * 60 * 60 * 1000)) ] - ] - ], function (error) { - if (error) cb(error); - else cb(); - }); - }); +exports.close = function(cb) { + driver.close(function(err) { + ready = false; + cb(err); }); -} - -/* takes an argument object including email, password hash, and pubkey. */ -exports.stageUser = function(obj) { - var secret = generateSecret(); - - // overwrite previously staged users - g_staged[secret] = { - type: "add_account", - email: obj.email, - pubkey: obj.pubkey, - pass: obj.hash - }; - - g_stagedEmails[obj.email] = secret; - return secret; }; -/* takes an argument object including email, pass, and pubkey. */ -// XXX: change to async -exports.stageEmail = function(existing_email, new_email, pubkey) { - var secret = generateSecret(); - // overwrite previously staged users - g_staged[secret] = { - type: "add_email", - existing_email: existing_email, - email: new_email, - pubkey: pubkey - }; - g_stagedEmails[new_email] = secret; - return secret; -}; - -/* invoked when a user clicks on a verification URL in their email */ -exports.gotVerificationSecret = function(secret, cb) { - if (!g_staged.hasOwnProperty(secret)) return cb("unknown secret"); - - // simply move from staged over to the emails "database" - var o = g_staged[secret]; - delete g_staged[secret]; - delete g_stagedEmails[o.email]; - if (o.type === 'add_account') { - exports.emailKnown(o.email, function(known) { - function createAccount() { - executeTransaction([ - [ "INSERT INTO users (password) VALUES(?)", [ o.pass ] ] , - [ "INSERT INTO emails (user, address) VALUES(last_insert_rowid(),?)", [ o.email ] ], - [ "INSERT INTO keys (email, key, expires) VALUES(last_insert_rowid(),?,?)", - [ o.pubkey, ((new Date()).getTime() + (14 * 24 * 60 * 60 * 1000)) ] - ] - ], function (error) { - if (error) cb(error); - else cb(); - }); - } - - // if this email address is known and a user has completed a re-verification of this email - // address, remove the email from the old account that it was associated with, and then - // create a brand new account with only this email. - // NOTE: this might be sub-optimal, but it's a dead simple approach that mitigates many attacks - // and gives us reasonable behavior (without explicitly supporting) in the face of shared email - // addresses. - if (known) { - exports.removeEmail(o.email, o.email, function (err) { - if (err) cb(err); - else createAccount(); - }); - } else { - createAccount(); - } - }); - } else if (o.type === 'add_email') { - exports.emailKnown(o.email, function(known) { - function addIt() { - addEmailToAccount(o.existing_email, o.email, o.pubkey, cb); - } - if (known) { - exports.removeEmail(o.email, o.email, function (err) { - if (err) cb(err); - else addIt(); - }); - } else { - addIt(); - } - }); - } else { - cb("internal error"); - } -}; - -// check authentication credentials for a given email address. This will invoke the -// users callback with the authentication (password/hash/whatever - the database layer -// doesn't care). callback will be passed undefined if email cannot be found -exports.checkAuth = function(email, cb) { - db.execute("SELECT users.password FROM emails, users WHERE users.id = emails.user AND emails.address = ?", - [ email ], - function (error, rows) { - cb(rows.length !== 1 ? undefined : rows[0].password); - }); +// accepts a function that will be invoked once the database is ready for transactions. +// this hook is important to pause the rest of application startup until async database +// connection establishment is complete. +exports.onReady = function(f) { + setTimeout(function() { + if (ready) f(); + else waiting.push(f); + }, 0); }; -function emailHasPubkey(email, pubkey, cb) { - db.execute( - 'SELECT keys.key FROM keys, emails WHERE emails.address = ? AND keys.email = emails.id AND keys.key = ?', - [ email, pubkey ], - function(err, rows) { - cb(rows.length === 1); - }); -} - -/* a high level operation that attempts to sync a client's view with that of the - * server. email is the identity of the authenticated channel with the user, - * identities is a map of email -> pubkey. - * We'll return an object that expresses three different types of information: - * there are several things we need to express: - * 1. emails that the client knows about but we do not - * 2. emails that we know about and the client does not - * 3. emails that we both know about but who need to be re-keyed - * NOTE: it's not neccesary to differentiate between #2 and #3, as the client action - * is the same (regen keypair and tell us about it). - */ -exports.getSyncResponse = function(email, identities, cb) { - var respBody = { - unknown_emails: [ ], - key_refresh: [ ] +[ + 'emailKnown', + 'isStaged', + 'emailsBelongToSameAccount', + 'addKeyToEmail', + 'stageUser', + 'stageEmail', + 'gotVerificationSecret', + 'checkAuth', + 'getSyncResponse', + 'pubkeysForEmail', + 'removeEmail', + 'cancelAccount' +].forEach(function(fn) { + exports[fn] = function() { + checkReady(); + driver[fn].apply(undefined, arguments); }; - - // get the user id associated with this account - emailToUserID(email, function(userID) { - if (userID === undefined) { - cb("no such email: " + email); - return; - } - db.execute( - 'SELECT address FROM emails WHERE ? = user', - [ userID ], - function (err, rows) { - if (err) cb(err); - else { - var emails = [ ]; - var keysToCheck = [ ]; - for (var i = 0; i < rows.length; i++) emails.push(rows[i].address); - - // #1 - for (var e in identities) { - if (emails.indexOf(e) == -1) respBody.unknown_emails.push(e); - else keysToCheck.push(e); - } - - // #2 - for (var e in emails) { - e = emails[e]; - if (!identities.hasOwnProperty(e)) respBody.key_refresh.push(e); - - } - - // #3 -- yes, this is sub-optimal in terms of performance. when we - // move away from public keys this will be unnec. - if (keysToCheck.length) { - var checked = 0; - keysToCheck.forEach(function(e) { - emailHasPubkey(e, identities[e], function(v) { - checked++; - if (!v) respBody.key_refresh.push(e); - if (checked === keysToCheck.length) { - cb(undefined, respBody); - } - }); - }); - } else { - cb(undefined, respBody); - } - } - }); - }); -}; - -// get all public keys associated with an email address -exports.pubkeysForEmail = function(identity, cb) { - db.execute( - 'SELECT keys.key FROM keys, emails WHERE emails.address = ? AND keys.email = emails.id', - [ identity ], - function(err, rows) { - var keys = undefined; - if (!err && rows && rows.length) { - keys = [ ]; - for (var i = 0; i < rows.length; i++) keys.push(rows[i].key); - } - cb(keys); - }); -}; - -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(); - }); - }); -}; - -exports.cancelAccount = function(authenticated_email, cb) { - emailToUserID(authenticated_email, function(user_id) { - executeTransaction([ - [ "delete from emails where user = ?", [ user_id ] ] , - [ "delete from keys where email in (select address from emails where user = ?)", [ user_id ] ], - [ "delete from users where id = ?", [ user_id ] ], - ], function (error) { - if (error) cb(error); - else cb(); - }); - }); -}; +}); diff --git a/browserid/lib/db_json.js b/browserid/lib/db_json.js new file mode 100644 index 0000000000000000000000000000000000000000..608476895e7c57c7bc68d7b73633854551461e60 --- /dev/null +++ b/browserid/lib/db_json.js @@ -0,0 +1,357 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* db_json is a json database driver. It is designed for use in + * local development, is intended to be extremely easy to maintain, + * have minimal dependencies on 3rd party libraries, and we could + * care less if it performs well with more than 10 or so users. + */ +const +path = require('path'), +fs = require('fs'), +secrets = require('./secrets'), +jsel = require('JSONSelect'); + +// a little alias for stringify +const ESC = JSON.stringify; + +var VAR_DIR = path.join(path.dirname(__dirname), "var"); + +var dbPath = path.join(VAR_DIR, "authdb.json"); + +/* The JSON database. The structure is thus: + * [ + * { + * password: "somepass", + * emails: [ + * { + * address: "lloyd@hilaiel.com", + * keys: [ + * { + * key: "SOMESTRINGOFTEXT", + * expires: 1231541615125 + * } + * ] + * } + * ] + * } + * ] + */ + +var db = []; +var stagedEmails = { }; +var staged = { }; + +function flush() { + fs.writeFileSync(dbPath, JSON.stringify(db)); +} + +// when should a key created right now expire? +function getExpiryTime() { + return ((new Date()).getTime() + (14 * 24 * 60 * 60 * 1000)); +} + +exports.open = function(cfg, cb) { + if (cfg && cfg.path) dbPath = cfg.path; + try { + db = JSON.parse(fs.readFileSync(dbPath)); + } catch(e) { + } + + setTimeout(cb, 0); +}; + +exports.close = function(cb) { + flush(); + setTimeout(cb, 0); +}; + +exports.emailKnown = function(email, cb) { + var m = jsel.match(".address:val(" + ESC(email) + ")", db); + setTimeout(function() { cb(m.length > 0) }, 0); +}; + +exports.isStaged = function(email, cb) { + if (cb) { + setTimeout(function() { + cb(stagedEmails.hasOwnProperty(email)); + }, 0); + } +}; + +exports.emailsBelongToSameAccount = function(lhs, rhs, cb) { + emailToUserID(lhs, function(lhs_uid) { + emailToUserID(rhs, function(rhs_uid) { + cb(lhs_uid === rhs_uid); + }, function (error) { + cb(false); + }); + }, function (error) { + cb(false); + }); +}; + +function addEmailToAccount(existing_email, email, pubkey, cb) { + emailToUserID(existing_email, function(userID) { + if (userID == undefined) { + cb("no such email: " + existing_email, undefined); + } else { + db[userID].emails.push({ + address: email, + keys: [ + { + key: pubkey, + expires: getExpiryTime() + } + ] + }); + flush(); + cb(); + } + }); +} + +exports.addKeyToEmail = function(existing_email, email, pubkey, cb) { + emailToUserID(existing_email, function(userID) { + if (userID == undefined) { + cb("no such email: " + existing_email, undefined); + return; + } + + if (!(db[userID].emails)) { + db[userID].emails = [ ]; + } + + var m = jsel.match("object:has(.address:val(" + ESC(email) + ")) > .keys", db[userID].emails); + + var kobj = { + key: pubkey, + expires: getExpiryTime() + }; + + if (m.length) { + m[0].push(kobj); + } else { + db[userID].emails.push({ + address: email, + keys: [ kobj ] + }); + } + + flush(); + if (cb) setTimeout(function() { cb(); }, 0); + }); +} + +exports.stageUser = function(obj, cb) { + var secret = secrets.generate(48); + + // overwrite previously staged users + staged[secret] = { + type: "add_account", + email: obj.email, + pubkey: obj.pubkey, + pass: obj.hash + }; + + stagedEmails[obj.email] = secret; + setTimeout(function() { cb(secret); }, 0); +}; + +exports.stageEmail = function(existing_email, new_email, pubkey, cb) { + var secret = secrets.generate(48); + // overwrite previously staged users + staged[secret] = { + type: "add_email", + existing_email: existing_email, + email: new_email, + pubkey: pubkey + }; + stagedEmails[new_email] = secret; + setTimeout(function() { cb(secret); }, 0); +}; + +exports.gotVerificationSecret = function(secret, cb) { + if (!staged.hasOwnProperty(secret)) return cb("unknown secret"); + + // simply move from staged over to the emails "database" + var o = staged[secret]; + delete staged[secret]; + delete stagedEmails[o.email]; + if (o.type === 'add_account') { + exports.emailKnown(o.email, function(known) { + function createAccount() { + db.push({ + password: o.pass, + emails: [ + { + address: o.email, + keys: [ { + key: o.pubkey, + expires: getExpiryTime(), + } ] + } + ] + }); + flush(); + cb(); + } + + // if this email address is known and a user has completed a re-verification of this email + // address, remove the email from the old account that it was associated with, and then + // create a brand new account with only this email. + // NOTE: this might be sub-optimal, but it's a dead simple approach that mitigates many attacks + // and gives us reasonable behavior (without explicitly supporting) in the face of shared email + // addresses. + + if (known) { + exports.removeEmail(o.email, o.email, function (err) { + if (err) cb(err); + else createAccount(); + }); + } else { + createAccount(); + } + }); + } else if (o.type === 'add_email') { + exports.emailKnown(o.email, function(known) { + function addIt() { + addEmailToAccount(o.existing_email, o.email, o.pubkey, cb); + } + if (known) { + exports.removeEmail(o.email, o.email, function (err) { + if (err) cb(err); + else addIt(); + }); + } else { + addIt(); + } + }); + } else { + cb("internal error"); + } +}; + +exports.checkAuth = function(email, cb) { + var m = jsel.match(":root > object:has(.address:val(" + ESC(email) + ")) > .password", db); + if (m.length === 0) m = undefined; + else m = m[0]; + setTimeout(function() { cb(m) }, 0); +}; + +function emailToUserID(email, cb) { + var id = undefined; + + for (var i = 0; i < db.length; i++) { + if (jsel.match(".address:val(" + JSON.stringify(email) + ")", db[i]).length) { + id = i; + break; + } + if (id !== undefined) break; + } + + setTimeout(function() { cb(id); }, 0); +} + +exports.getSyncResponse = function(email, identities, cb) { + var respBody = { + unknown_emails: [ ], + key_refresh: [ ] + }; + + // get the user id associated with this account + emailToUserID(email, function(userID) { + if (userID === undefined) { + cb("no such email: " + email); + return; + } + var emails = jsel.match(".address", db[userID]); + var keysToCheck = [ ]; + + // #1 emails that the client knows about but we do not + for (var e in identities) { + if (emails.indexOf(e) == -1) respBody.unknown_emails.push(e); + else keysToCheck.push(e); + } + + // #2 emails that we know about and the client does not + for (var e in emails) { + e = emails[e]; + if (!identities.hasOwnProperty(e)) respBody.key_refresh.push(e); + } + + // #3 emails that we both know about but who need to be re-keyed + if (keysToCheck.length) { + var checked = 0; + keysToCheck.forEach(function(e) { + if (!jsel.match(".key:val(" + ESC(identities[e]) + ")", db[userID]).length) + respBody.key_refresh.push(e); + checked++; + if (checked === keysToCheck.length) cb(undefined, respBody); + }); + } else { + cb(undefined, respBody); + } + }); +}; + +exports.pubkeysForEmail = function(identity, cb) { + var m = jsel.match(".emails object:has(.address:val(" + ESC(identity)+ ")) .key", db); + setTimeout(function() { cb(m); }, 0); +}; + +exports.removeEmail = function(authenticated_email, email, cb) { + var m = jsel.match(":root > object:has(.address:val("+ESC(authenticated_email)+")):has(.address:val("+ESC(email)+")) .emails", db); + + if (m.length) { + var emails = m[0]; + for (var i = 0; i < emails.length; i++) { + if (emails[i].address === email) { + emails.splice(i, 1); + break; + } + } + } + + setTimeout(function() { cb(); }, 0); +}; + +exports.cancelAccount = function(authenticated_email, cb) { + emailToUserID(authenticated_email, function(user_id) { + db.splice(user_id, 1); + flush(); + cb(); + }); +}; diff --git a/browserid/lib/db_mysql.js b/browserid/lib/db_mysql.js new file mode 100644 index 0000000000000000000000000000000000000000..1fb2fd8ce2e2f72a778d08b669ecc99bd09b73bd --- /dev/null +++ b/browserid/lib/db_mysql.js @@ -0,0 +1,457 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* This is a mysql driver for the browserid server. It maps the data + * storage requirements of browserid onto a relational schema. This + * driver is intended to be fast and scalable. + */ + +/* + * The Schema: + * + * +--- user ------+ +--- email ----+ +--- pubkey -----+ + * |*int id | <-\ |*int id | <-\ |*int id | + * | string passwd | \- |*int user | \-- |*int email | + * +---------------+ |*string address | string pubkey | + * +--------------+ | int expires | + * +----------------+ + * + * + * +------ staged ----------+ + * |*string secret | + * | bool new_acct | + * | string existing | + * |*string email | + * | string pubkey | + * | string passwd | + * | timestamp ts | + * +------------------------+ + */ + +const +mysql = require('mysql'), +secrets = require('./secrets'), +logger = require('../../libs/logging.js'); + +var client = undefined; + +// may get defined at open() time causing a database to be dropped upon connection closing. +var drop_on_close = undefined; + +const schemas = [ + "CREATE TABLE IF NOT EXISTS user ( id INTEGER AUTO_INCREMENT PRIMARY KEY, passwd VARCHAR(64) );", + "CREATE TABLE IF NOT EXISTS email ( id INTEGER AUTO_INCREMENT PRIMARY KEY, user INTEGER, address VARCHAR(255) UNIQUE, INDEX(address) );", + "CREATE TABLE IF NOT EXISTS pubkey ( id INTEGER AUTO_INCREMENT PRIMARY KEY, email INTEGER, content TEXT, expiry DATETIME );", + "CREATE TABLE IF NOT EXISTS staged ( secret VARCHAR(48) PRIMARY KEY, new_acct BOOL, existing VARCHAR(255), email VARCHAR(255) UNIQUE, INDEX(email), pubkey TEXT, passwd VARCHAR(64), ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP);" +]; + +// log an unexpected database error +function logUnexpectedError(detail) { + // first, get line number of callee + var where; + try { dne; } catch (e) { where = e.stack.split('\n')[2].trim(); }; + // now log it! + logger.log('db', { type: "unexpected", message: "unexpected database failure", detail: detail, where: where }); +} + +// open & create the mysql database +exports.open = function(cfg, cb) { + if (client) throw "database is already open!"; + client = new mysql.Client(); + // mysql config requires + const defParams = { + host: '127.0.0.1', + port: "3306", + user: 'test', + password: 'pass', + unit_test: false + }; + + Object.keys(defParams).forEach(function(param) { + client[param] = cfg[param] ? cfg[param] : defParams[param]; + }); + + // let's figure out the database name + var database = cfg.database; + if (!database) database = "browserid"; + if (cfg.unit_test) { + database += "_" + secrets.generate(8); + drop_on_close = database; + } + + client.connect(function(error) { + if (error) { + logUnexpectedError(error); + cb(error); + } else { + // now create the databse + client.query("CREATE DATABASE IF NOT EXISTS " + database, function(err) { + if (err) { + logUnexpectedError(err); + cb(err); + return; + } + client.useDatabase(database, function(err) { + if (err) { + logUnexpectedError(err); + cb(err); + return; + } + + // now create tables + function createNextTable(i) { + if (i < schemas.length) { + client.query(schemas[i], function(err) { + if (err) { + logUnexpectedError(err); + cb(err); + } else { + createNextTable(i+1); + } + }); + } else { + cb(); + } + } + createNextTable(0); + }); + }); + } + }); +}; + +exports.close = function(cb) { + function endConn() { + client.end(function(err) { + client = undefined; + if (err) logUnexpectedError(err); + if (cb) cb(err); + }); + } + // when unit_test is specified at open time, we use a temporary database, + // and clean it up upon close. + if (drop_on_close) { + client.query("DROP DATABASE " + drop_on_close, function() { + endConn(); + }); + } else { + endConn(); + } +}; + +exports.emailKnown = function(email, cb) { + client.query( + "SELECT COUNT(*) as N FROM email WHERE address = ?", [ email ], + function(err, rows) { + if (err) logUnexpectedError(err); + cb(rows && rows.length > 0 && rows[0].N > 0); + } + ); +} + +exports.isStaged = function(email, cb) { + client.query( + "SELECT COUNT(*) as N FROM staged WHERE email = ?", [ email ], + function(err, rows) { + if (err) logUnexpectedError(err); + cb(rows && rows.length > 0 && rows[0].N > 0); + } + ); +} + +exports.stageUser = function(obj, cb) { + var secret = secrets.generate(48); + // overwrite previously staged users + client.query('INSERT INTO staged (secret, new_acct, email, pubkey, passwd) VALUES(?,TRUE,?,?,?) ' + + 'ON DUPLICATE KEY UPDATE secret=?, existing="", new_acct=TRUE, pubkey=?, passwd=?', + [ secret, obj.email, obj.pubkey, obj.hash, secret, obj.pubkey, obj.hash], + function(err) { + if (err) { + logUnexpectedError(err); + cb(undefined, err); + } else cb(secret); + }); +} + +exports.gotVerificationSecret = function(secret, cb) { + client.query( + "SELECT * FROM staged WHERE secret = ?", [ secret ], + function(err, rows) { + if (err) { + logUnexpectedError(err); + cb(err); + } else if (rows.length === 0) cb("unknown secret"); + else { + var o = rows[0]; + + function addEmailAndPubkey(userID) { + client.query( + "INSERT INTO email(user, address) VALUES(?, ?)", + [ userID, o.email ], + function(err, info) { + if (err) { logUnexpectedError(err); cb(err); return; } + addKeyToEmailRecord(info.insertId, o.pubkey, cb); + }); + } + + // delete the record + client.query("DELETE LOW_PRIORITY FROM staged WHERE secret = ?", [ secret ]); + + if (o.new_acct) { + // we're creating a new account, add appropriate entries into user, email, and pubkey. + client.query( + "INSERT INTO user(passwd) VALUES(?)", + [ o.passwd ], + function(err, info) { + if (err) { logUnexpectedError(err); cb(err); return; } + addEmailAndPubkey(info.insertId); + }); + } else { + // we're adding an email address to an existing user account. add appropriate entries into email and + // pubkey + client.query( + "SELECT user FROM email WHERE address = ?", [ o.existing ], + function(err, rows) { + if (err) { logUnexpectedError(err); cb(err); } + else if (rows.length === 0) cb("cannot find email address: " + o.existing); + else { + addEmailAndPubkey(rows[0].user); + } + }); + } + } + } + ); +} + +exports.emailsBelongToSameAccount = function(lhs, rhs, cb) { + client.query( + 'SELECT COUNT(*) AS n FROM email WHERE address = ? AND user = ( SELECT user FROM email WHERE address = ? );', + [ lhs, rhs ], + function (err, rows) { + if (err) cb(false); + else cb(rows.length === 1 && rows[0].n === 1); + }); +} + +function addKeyToEmailRecord(emailId, pubkey, cb) { + client.query( + // XXX: 2 weeks is wrong, but then so is keypairs. + "INSERT INTO pubkey(email, content, expiry) VALUES(?, ?, DATE_ADD(NOW(), INTERVAL 2 WEEK))", + [ emailId, pubkey ], + function(err, info) { + if (err) logUnexpectedError(err); + // smash null into undefined. + cb(err ? err : undefined); + }); +} + +exports.addKeyToEmail = function(existing_email, email, pubkey, cb) { + // this function will NOT add a new email address to a user record. The only + // way that happens is when a verification secret is provided to us. Limiting + // the code paths that result in us concluding that a user owns an email address + // is a Good Thing. + exports.emailsBelongToSameAccount(existing_email, email, function(ok) { + if (!ok) { + cb("authenticated user doesn't have permission to add a public key to " + email); + return; + } + + // now we know that the user has permission to add a key. + client.query( + "SELECT id FROM email WHERE address = ?", [ email ], + function(err, rows) { + if (err) { logUnexpectedError(err); cb(err); } + else if (rows.length === 0) cb("cannot find email address: " + email); + else { + addKeyToEmailRecord(rows[0].id, pubkey, cb); + } + }); + }); +} + +exports.stageEmail = function(existing_email, new_email, pubkey, cb) { + var secret = secrets.generate(48); + // overwrite previously staged users + client.query('INSERT INTO staged (secret, new_acct, existing, email, pubkey) VALUES(?,FALSE,?,?,?) ' + + 'ON DUPLICATE KEY UPDATE secret=?, existing=?, new_acct=FALSE, pubkey=?, passwd=""', + [ secret, existing_email, new_email, pubkey, secret, existing_email, pubkey], + function(err) { + if (err) { + logUnexpectedError(err); + cb(undefined, err); + } + else cb(secret); + }); +} + +exports.checkAuth = function(email, cb) { + client.query( + 'SELECT passwd FROM user WHERE id = ( SELECT user FROM email WHERE address = ? )', + [ email ], + function (err, rows) { + if (err) logUnexpectedError(err); + cb((rows && rows.length == 1) ? rows[0].passwd : undefined); + }); +} + +function emailHasPubkey(email, pubkey, cb) { + client.query( + 'SELECT pubkey.content FROM pubkey, email WHERE email.address = ? AND pubkey.email = email.id AND pubkey.content = ?', + [ email, pubkey ], + function(err, rows) { + if (err) logUnexpectedError(err); + cb(rows && rows.length === 1); + }); +} + +/* a high level operation that attempts to sync a client's view with that of the + * server. email is the identity of the authenticated channel with the user, + * identities is a map of email -> pubkey. + * We'll return an object that expresses three different types of information: + * there are several things we need to express: + * 1. emails that the client knows about but we do not + * 2. emails that we know about and the client does not + * 3. emails that we both know about but who need to be re-keyed + * NOTE: it's not neccesary to differentiate between #2 and #3, as the client action + * is the same (regen keypair and tell us about it). + */ +exports.getSyncResponse = function(email, identities, cb) { + var respBody = { + unknown_emails: [ ], + key_refresh: [ ] + }; + + client.query( + 'SELECT address FROM email WHERE user = ( SELECT user FROM email WHERE address = ? ) ', + [ email ], + function (err, rows) { + if (err) cb(err); + else { + var emails = [ ]; + var keysToCheck = [ ]; + for (var i = 0; i < rows.length; i++) emails.push(rows[i].address); + + // #1 + for (var e in identities) { + if (emails.indexOf(e) == -1) respBody.unknown_emails.push(e); + else keysToCheck.push(e); + } + + // #2 + for (var e in emails) { + e = emails[e]; + if (!identities.hasOwnProperty(e)) respBody.key_refresh.push(e); + } + + // #3 -- yes, this is sub-optimal in terms of performance. when we + // move away from public keys this will be unnec. + if (keysToCheck.length) { + var checked = 0; + keysToCheck.forEach(function(e) { + emailHasPubkey(e, identities[e], function(v) { + checked++; + if (!v) respBody.key_refresh.push(e); + if (checked === keysToCheck.length) { + cb(undefined, respBody); + } + }); + }); + } else { + cb(undefined, respBody); + } + } + }); +}; + + +exports.pubkeysForEmail = function(email, cb) { + client.query( + 'SELECT content FROM pubkey WHERE email = (SELECT id FROM email WHERE address = ?)', + [ email ], + function (err, rows) { + var ar = [ ]; + if (!err) rows.forEach(function(r) { ar.push(r.content); }); + else logUnexpectedError(err); + cb(ar); + }); +} + +exports.removeEmail = function(authenticated_email, email, cb) { + exports.emailsBelongToSameAccount(authenticated_email, email, function(ok) { + if (!ok) { + logger.log('security', authenticated_email + ' attempted to delete an email that doesn\'t belong to her: ' + email); + cb("authenticated user doesn't have permission to remove specified email " + email); + return; + } + + client.query( + 'DELETE FROM pubkey WHERE email = ( SELECT id FROM email WHERE address = ? )', + [ email ], + function (err, info) { + if (err) { + logUnexpectedError(err); + cb(err); + } else { + client.query( + 'DELETE FROM email WHERE address = ?', + [ email ], + function(err, info) { + if (err) logUnexpectedError(err); + // smash null into undefined + cb(err ? err : undefined); + }); + } + }); + }); +} + +exports.cancelAccount = function(email, cb) { + function reportErr(err) { if (err) logUnexpectedError(err); } + client.query( + "SELECT user FROM email WHERE address = ?", [ email ], + function (err, rows) { + if (err) { + logUnexpectedError(err) + cb(err); + return + } + var uid = rows[0].user; + client.query("DELETE LOW_PRIORITY FROM pubkey WHERE email in ( SELECT id FROM email WHERE user = ? )", [ uid ], reportErr); + client.query("DELETE LOW_PRIORITY FROM email WHERE user = ?", [ uid ], reportErr); + client.query("DELETE LOW_PRIORITY FROM user WHERE id = ?", [ uid ], reportErr); + cb(); + }); +} diff --git a/browserid/lib/email.js b/browserid/lib/email.js index 9a5f56475308def4b2b63f271dc1050aec384d01..47157e14ab16d7445485f76b0e88e4a5fffa26ed 100644 --- a/browserid/lib/email.js +++ b/browserid/lib/email.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const db = require('./db'), emailer = require('nodemailer'), diff --git a/browserid/lib/httputils.js b/browserid/lib/httputils.js index 96e8a30c906dd86ae08559daeff6373626d6bddd..f543d403fa1ca703d5f55d48cf92f401f08565da 100644 --- a/browserid/lib/httputils.js +++ b/browserid/lib/httputils.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // various little utilities to make crafting boilerplate responses // simple diff --git a/browserid/lib/secrets.js b/browserid/lib/secrets.js index 7aca40b986e7e82366fd531e22421f17f57b7dff..b57bf0ea3a0e57fcba6487ec13e118348bec6336 100644 --- a/browserid/lib/secrets.js +++ b/browserid/lib/secrets.js @@ -1,11 +1,46 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const path = require('path'), fs = require('fs'); -function generateSecret() { +exports.generate = function(chars) { var str = ""; const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - for (var i=0; i < 128; i++) { + for (var i=0; i < chars; i++) { str += alphabet.charAt(Math.floor(Math.random() * alphabet.length)); } return str; @@ -19,7 +54,7 @@ exports.hydrateSecret = function(name, dir) { try{ secret = fs.readFileSync(p).toString(); } catch(e) {}; if (secret === undefined) { - secret = generateSecret(); + secret = exports.generate(128); fs.writeFileSync(p, secret); } return secret; diff --git a/browserid/lib/webfinger.js b/browserid/lib/webfinger.js index f79045b48db076db08c603613dffcece05119064..b7eb85b2d36154aa0cb4196c3efae460a15d96bf 100644 --- a/browserid/lib/webfinger.js +++ b/browserid/lib/webfinger.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const db = require('./db.js'), fs = require('fs'), diff --git a/browserid/lib/wsapi.js b/browserid/lib/wsapi.js index e7d757956aa8ddae61e51ab6f7ccc4230ce0d0be..da4c3a2ce11362de844102a64e9b2c3e7880feda 100644 --- a/browserid/lib/wsapi.js +++ b/browserid/lib/wsapi.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // a module which implements the authorities web server api. // it used to be that we stuffed every function in exports. // now we're using proper express function registration to deal @@ -72,25 +107,26 @@ function setup(app) { try { // upon success, stage_user returns a secret (that'll get baked into a url // and given to the user), on failure it throws - var secret = db.stageUser(stageParams); - - // store the email being registered in the session data - if (!req.session) req.session = {}; + db.stageUser(stageParams, function(secret) { + // store the email being registered in the session data + if (!req.session) req.session = {}; - // store inside the session the details of this pending verification - req.session.pendingVerification = { - email: stageParams.email, - hash: stageParams.hash // we must store both email and password to handle the case where - // a user re-creates an account - specifically, registration status - // must ensure the new credentials work to properly verify that - // the user has clicked throught the email link. note, this salted, bcrypted - // representation of a user's password will get thrust into an encrypted cookie - // served over an encrypted (SSL) session. guten, yah. - }; + // store inside the session the details of this pending verification + req.session.pendingVerification = { + email: stageParams.email, + hash: stageParams.hash // we must store both email and password to handle the case where + // a user re-creates an account - specifically, registration status + // must ensure the new credentials work to properly verify that + // the user has clicked throught the email link. note, this salted, bcrypted + // representation of a user's password will get thrust into an encrypted cookie + // served over an encrypted (SSL) session. guten, yah. + }; - resp.json(true); - email.sendVerificationEmail(stageParams.email, stageParams.site, secret); + resp.json(true); + // let's now kick out a verification email! + email.sendVerificationEmail(stageParams.email, stageParams.site, secret); + }); } catch(e) { // we should differentiate tween' 400 and 500 here. httputils.badRequest(resp, e.toString()); @@ -128,7 +164,6 @@ function setup(app) { } else { // this is a pending registration, let's check if the creds stored on the // session are good yet. - var v = req.session.pendingVerification; db.checkAuth(v.email, function(hash) { if (hash === v.hash) { @@ -161,17 +196,17 @@ function setup(app) { app.post('/wsapi/add_email', checkAuthed, checkParams(["email", "pubkey", "site"]), function (req, resp) { try { - // upon success, stage_user returns a secret (that'll get baked into a url - // and given to the user), on failure it throws - var secret = db.stageEmail(req.session.authenticatedUser, req.body.email, req.body.pubkey); + // on failure stageEmail may throw + db.stageEmail(req.session.authenticatedUser, req.body.email, req.body.pubkey, function(secret) { - // store the email being added in session data - req.session.pendingAddition = req.body.email; + // store the email being added in session data + req.session.pendingAddition = req.body.email; - resp.json(true); + resp.json(true); - // let's now kick out a verification email! - email.sendVerificationEmail(req.body.email, req.body.site, secret); + // let's now kick out a verification email! + email.sendVerificationEmail(req.body.email, req.body.site, secret); + }); } catch(e) { // we should differentiate tween' 400 and 500 here. httputils.badRequest(resp, e.toString()); diff --git a/browserid/run.js b/browserid/run.js index ed8b03dbe38bb9cde7f09640deb67fa27ce96a6c..e83192d2fdf67955d34cf8ddd0d03f0f9c01df39 100755 --- a/browserid/run.js +++ b/browserid/run.js @@ -1,5 +1,40 @@ #!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + var path = require("path"), fs = require("fs"), express = require("express"); diff --git a/browserid/static/css/style.css b/browserid/static/css/style.css index 0a94ef5ea99e6ee4ac4171169a60b3bd5828cf98..9944eb2906632e0782d519c3488097c03f9e13f4 100644 --- a/browserid/static/css/style.css +++ b/browserid/static/css/style.css @@ -181,6 +181,12 @@ footer .copyright { padding: 0; } +#steps a { + color: #666; + text-decoration: none; + border-bottom: 1px dotted #666; +} + .step { margin: 1em 0 2em 0; padding: 0 0 0 50px; @@ -222,7 +228,7 @@ footer .copyright { font-size: 1.2em; } - pre code { +pre code { padding: 10px 15px 10px 15px; margin: .75em; -webkit-border-radius: 10px; diff --git a/browserid/static/dialog/controllers/dialog_controller.js b/browserid/static/dialog/controllers/dialog_controller.js index 6fdb1477aa9bb6a8aaae06a01aae1145f7411458..995b16440e8b78d47f3fbead47e12bcd59fb5219 100644 --- a/browserid/static/dialog/controllers/dialog_controller.js +++ b/browserid/static/dialog/controllers/dialog_controller.js @@ -1,5 +1,40 @@ /*jshint brgwser:true, jQuery: true, forin: true, laxbreak:true */ -/*global Channel:true, CryptoStubs:true, alert:true, errorOut:true, setupChannel:true, getEmails:true, clearEmails: true, console: true, _: true, pollTimeout: true, addEmail: true, removeEmail:true, BrowserIDNetwork: true, BrowserIDWait:true, BrowserIDErrors: true, runErrorDialog:true */ +/*global Channel:true, CryptoStubs:true, alert:true, errorOut:true, setupChannel:true, getEmails:true, clearEmails: true, console: true, _: true, pollTimeout: true, addEmail: true, removeEmail:true, BrowserIDNetwork: true, BrowserIDWait:true, BrowserIDErrors: true */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // // a JMVC controller for the browserid dialog // @@ -144,7 +179,7 @@ PageController.extend("Dialog", {}, { // email, keypair, and that fact self.persistAddressAndKeyPair(self.confirmEmail, self.confirmKeypair, "browserid.org:443"); - self.syncidentities(); + self.syncIdentities(); }, diff --git a/browserid/static/dialog/dialog.js b/browserid/static/dialog/dialog.js index 5ac3581f1af28ba9f7bad62e1ff2358b5b8fe189..ac0019d157f8092d7aec3ac45cbc1d80780b8c13 100644 --- a/browserid/static/dialog/dialog.js +++ b/browserid/static/dialog/dialog.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + /*globals steal */ steal.plugins( diff --git a/browserid/static/dialog/register_iframe.js b/browserid/static/dialog/register_iframe.js index c2da36defa52957ec807e68f3f6f3b1e9f2c77b8..42494702a9e5792f36c20e8630bfdf67a2f0bddb 100644 --- a/browserid/static/dialog/register_iframe.js +++ b/browserid/static/dialog/register_iframe.js @@ -1,6 +1,38 @@ -/*jshint browser:true, jQuery: true, forin: true */ -/*global Channel:true, CryptoStubs:true, alert:true, errorOut:true */ - +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // this is the picker code! it runs in the identity provider's domain, and // fiddles the dom expressed by picker.html (function() { diff --git a/browserid/static/dialog/resources/channel.js b/browserid/static/dialog/resources/channel.js index 8f08018fc62acdb6c415363f7526d63a18bb00cc..43aa6703fb4c8d72d6a5b8c059c259dd4250d1d1 100644 --- a/browserid/static/dialog/resources/channel.js +++ b/browserid/static/dialog/resources/channel.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + /*global alert:true, setupNativeChannel:true, setupHTMLChannel:true, Channel:true */ function errorOut(trans, code) { function getVerboseMessage(code) { diff --git a/browserid/static/dialog/resources/crypto-api.js b/browserid/static/dialog/resources/crypto-api.js index 3eeec8c946f93835c19af2e97a20e923d703b81b..76b39ff1e86f7508060c4b07b791436a951f1d5e 100644 --- a/browserid/static/dialog/resources/crypto-api.js +++ b/browserid/static/dialog/resources/crypto-api.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + /*global CryptoStubs:true */ // This file is the cryptographic routines that are required for // BrowserID's HTML5 implementation diff --git a/browserid/static/dialog/resources/main.js b/browserid/static/dialog/resources/main.js index 6b2053d331529a77cfd7b76eedb7d57b9f7bce77..897dcb99b4281f0103b980c0e2a3c78dd657ed90 100644 --- a/browserid/static/dialog/resources/main.js +++ b/browserid/static/dialog/resources/main.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // this is the picker code! it runs in the identity provider's domain, and // fiddles the dom expressed by picker.html var run = function() { diff --git a/browserid/static/dialog/resources/storage.js b/browserid/static/dialog/resources/storage.js index c8577e40c2f97631968a3651e2a6abe772b50fb7..0a97ee8149984de75bbe5463ec270fa6bbb57944 100644 --- a/browserid/static/dialog/resources/storage.js +++ b/browserid/static/dialog/resources/storage.js @@ -1,3 +1,37 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ var getEmails = function() { try { diff --git a/browserid/static/dialog/views/body.ejs b/browserid/static/dialog/views/body.ejs index 7b17ff10777bde550932a82b8babc700b22e9474..fe7538a603fec23471ede2b51ef7ec184a14817b 100644 --- a/browserid/static/dialog/views/body.ejs +++ b/browserid/static/dialog/views/body.ejs @@ -15,6 +15,6 @@ </form> <footer id="terms"> - BrowserID is a <a target="_blank" href="http://mozillalabs.org">Mozilla Labs</a> service. + BrowserID is a <a target="_blank" href="http://mozillalabs.com">Mozilla Labs</a> service. See our <a target="_blank" href="https://browserid.org/tos">terms</a> and <a target="_blank" href="https://browserid.org/privacy">privacy policy</a>, or <a target="_blank" href="https://browserid.org/users">learn more</a>. </footer> diff --git a/browserid/static/include.js b/browserid/static/include.js index 64b1ff758d4d6cb0ea8b269e08b99ba5d57702f7..b2083c867a5507225c4e0c476b86d9f629f7ed27 100644 --- a/browserid/static/include.js +++ b/browserid/static/include.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // this is the file that the RP includes to shim in the // navigator.id.getVerifiedEmail() function @@ -8,8 +43,9 @@ if (!navigator.id) { if (!navigator.id.getVerifiedEmail || navigator.id._getVerifiedEmailIsShimmed) { var ipServer = "https://browserid.org"; + var isMobile = navigator.userAgent.indexOf('Fennec/') != -1; - // local embedded copy of jschannel: http://github.com/mozilla/jschannel + // local embedded copy of jschannel: http://github.com/mozilla/jschannel var Channel = (function() { // current transaction id, start out at a random *odd* number between 1 and a million // There is one current transaction counter id per page, and it's shared between @@ -538,9 +574,8 @@ if (!navigator.id.getVerifiedEmail || navigator.id._getVerifiedEmailIsShimmed) function _open_window() { return window.open( - //ipServer + "/dialog/dialog/dialog.html", "_mozid_signin", - ipServer + "/sign_in", "_mozid_signin", - "menubar=0,location=0,resizable=0,scrollbars=0,status=0,dialog=1,width=520,height=350"); + ipServer + "/sign_in", "_mozid_signin", + isMobile ? undefined : "menubar=0,location=0,resizable=0,scrollbars=0,status=0,dialog=1,width=520,height=350"); } navigator.id.getVerifiedEmail = function(callback) { @@ -608,7 +643,7 @@ if (!navigator.id.getVerifiedEmail || navigator.id._getVerifiedEmailIsShimmed) navigator.id.getSpecificVerifiedEmail = function(email, token, onsuccess, onerror) { var doc = window.document; - // if we have a token, we should not be opening a window, rather we should be + // if we have a token, we should not be opening a window, rather we should be // able to do this entirely through IFRAMEs if (token) { var iframe = _create_iframe(doc); @@ -676,7 +711,7 @@ if (!navigator.id.getVerifiedEmail || navigator.id._getVerifiedEmailIsShimmed) cleanup(); } }); - }; + }; navigator.id._getVerifiedEmailIsShimmed = true; } diff --git a/browserid/static/js/browserid.js b/browserid/static/js/browserid.js index d13546d9dfae0c83a3a9001b83ac53df7e95270a..b497d80557276a21680b67f8c01eefa0a2be7683 100644 --- a/browserid/static/js/browserid.js +++ b/browserid/static/js/browserid.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + $(function() { if ($('#emailList')) { display_saved_ids(); diff --git a/browserid/tests/db-test.js b/browserid/tests/db-test.js index bd7afd9145bf30bb15b9d2d0f9c6a645b1c353be..c0a492ece0dcbe822a3842be7adb4fe59e949b36 100755 --- a/browserid/tests/db-test.js +++ b/browserid/tests/db-test.js @@ -1,5 +1,40 @@ #!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const assert = require('assert'), vows = require('vows'), @@ -12,364 +47,425 @@ var suite = vows.describe('db'); // disable vows (often flakey?) async error behavior suite.options.error = false; -db.dbPath = temp.path({suffix: '.sqlite'}); - -suite.addBatch({ - "waiting for the database to become ready": { - topic: function() { - var cb = this.callback; - db.onReady(function() { cb(true) }); - }, - "the database is ready": function(r) { - assert.strictEqual(r, true); - } - } -}); - -// caching of secrets between test batches. -var secret = undefined; +function addTestsForDriver(driver) { + var dbPath = temp.path({suffix: '.db'}); -suite.addBatch({ - "an email address is not reported as staged before it is": { - topic: function() { - return db.isStaged('lloyd@nowhe.re'); - }, - "isStaged returns false": function (r) { - assert.strictEqual(r, false); - } - }, - "an email address is not reported as known before it is": { - topic: function() { - db.emailKnown('lloyd@nowhe.re', this.callback); - }, - "emailKnown returns false": function (r) { - assert.strictEqual(r, false); - } - } -}); - -suite.addBatch({ - "stage a user for creation pending verification": { - topic: function() { - return secret = db.stageUser({ - email: 'lloyd@nowhe.re', - pubkey: 'fakepubkey', - hash: 'fakepasswordhash' - }); - }, - "staging returns a valid secret": function(r) { - assert.isString(secret); - assert.strictEqual(secret.length, 48); - } + if (driver === 'mysql') { + // let's check to see if we can connect and render a nice + // error message if not. For community members making casual + // contributions, we should expect that they might not want to + // set up mysql. + suite.addBatch({ + "mysql server": { + topic: function() { db.open({driver: driver, unit_test: true}, this.callback) }, + "accepting connections": function(err) { + if (err) { + console.log("MYSQL TESTS WILL FAIL cause cannot connect to a local mysql database (" + err.message + ")"); + } + }, + "connection closes": { + topic: function() { db.close(this.callback); }, + "without error": function(err) { + assert.isUndefined(err); + } + } + } + }); } -}); -suite.addBatch({ - "an email address is reported": { - topic: function() { - return db.isStaged('lloyd@nowhe.re'); + suite.addBatch({ + "onReady": { + topic: function() { db.onReady(this.callback); }, + "works": function(r) { } }, - " as staged after it is": function (r) { - assert.strictEqual(r, true); - } - }, - "an email address is not reported": { - topic: function() { - db.emailKnown('lloyd@nowhe.re', this.callback); + "onReady still": { + topic: function() { db.onReady(this.callback); }, + "works for more than one caller": function(r) { } }, - " as known when it is only staged": function (r) { - assert.strictEqual(r, false); - } - } -}); - -suite.addBatch({ - "upon receipt of a secret": { - topic: function() { - db.gotVerificationSecret(secret, this.callback); - }, - "gotVerificationSecret completes without error": function (r) { - assert.strictEqual(r, undefined); + "opening the database": { + topic: function() { + db.open({ driver: driver, unit_test: true, path: dbPath }, this.callback); + }, + "and its ready": function(r) { + assert.isUndefined(r); + }, + "doesn't prevent onReady": { + topic: function() { db.onReady(this.callback); }, + "from working": function(r) { } + } } - } -}); + }); -suite.addBatch({ - "an email address is not reported": { - topic: function() { - return db.isStaged('lloyd@nowhe.re'); - }, - "as staged immediately after its verified": function (r) { - assert.strictEqual(r, false); - } - }, - "an email address is known": { - topic: function() { - db.emailKnown('lloyd@nowhe.re', this.callback); - }, - "when it is": function (r) { - assert.strictEqual(r, true); - } - } -}); + // caching of secrets between test batches. + var secret = undefined; -suite.addBatch({ - "adding keys to email": { - topic: function() { - db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepubkey2', this.callback); - }, - "works": function(r) { - assert.isUndefined(r); - } - } -}); - -suite.addBatch({ - "adding multiple keys to email": { - topic: function() { - db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepubkey3', this.callback); + suite.addBatch({ + "an email address is not reported as staged before it is": { + topic: function() { + db.isStaged('lloyd@nowhe.re', this.callback); + }, + "isStaged returns false": function (r) { + assert.isFalse(r); + } }, - "works too": function(r) { - assert.isUndefined(r); + "an email address is not reported as known before it is": { + topic: function() { + db.emailKnown('lloyd@nowhe.re', this.callback); + }, + "emailKnown returns false": function (r) { + assert.isFalse(r); + } } - } -}); + }); -suite.addBatch({ - "pubkeysForEmail": { - topic: function() { - db.pubkeysForEmail('lloyd@nowhe.re', this.callback); - }, - "returns all public keys properly": function(r) { - assert.isArray(r); - assert.strictEqual(r.length, 3); + suite.addBatch({ + "stage a user for creation pending verification": { + topic: function() { + db.stageUser({ + email: 'lloyd@nowhe.re', + pubkey: 'fakepubkey', + hash: 'fakepasswordhash' + }, this.callback); + }, + "staging returns a valid secret": function(r) { + secret = r; + assert.isString(secret); + assert.strictEqual(secret.length, 48); + } } - } -}); + }); -suite.addBatch({ - "checkAuth returns": { - topic: function() { - db.checkAuth('lloyd@nowhe.re', this.callback); + suite.addBatch({ + "an email address is reported": { + topic: function() { + db.isStaged('lloyd@nowhe.re', this.callback); + }, + " as staged after it is": function (r) { + assert.strictEqual(r, true); + } }, - "the correct password": function(r) { - assert.strictEqual(r, "fakepasswordhash"); + "an email address is not reported": { + topic: function() { + db.emailKnown('lloyd@nowhe.re', this.callback); + }, + " as known when it is only staged": function (r) { + assert.strictEqual(r, false); + } } - } -}); + }); -suite.addBatch({ - "staging an email": { - topic: function() { - return db.stageEmail('lloyd@nowhe.re', 'lloyd@somewhe.re', 'fakepubkey4'); - }, - "yields a valid secret": function(secret) { - assert.isString(secret); - assert.strictEqual(secret.length, 48); - }, - "makes email addr via isStaged": { - topic: function() { return db.isStaged('lloyd@somewhe.re'); }, - "visible": function(r) { assert.isTrue(r); } - }, - "and verifying it": { - topic: function(secret) { + suite.addBatch({ + "upon receipt of a secret": { + topic: function() { db.gotVerificationSecret(secret, this.callback); }, - "returns no error": function(r) { - assert.isUndefined(r); - }, - "makes email addr via knownEmail": { - topic: function() { db.emailKnown('lloyd@somewhe.re', this.callback); }, - "visible": function(r) { assert.isTrue(r); } - }, - "makes email addr via isStaged": { - topic: function() { return db.isStaged('lloyd@somewhe.re'); }, - "not visible": function(r) { assert.isFalse(r); } + "gotVerificationSecret completes without error": function (r) { + assert.strictEqual(r, undefined); } } - } -}); + }); -// exports.emailsBelongToSameAccount -suite.addBatch({ - "emails do belong to the same account": { - "is true": { + suite.addBatch({ + "an email address is not reported": { topic: function() { - db.emailsBelongToSameAccount('lloyd@nowhe.re', 'lloyd@somewhe.re', this.callback); + db.isStaged('lloyd@nowhe.re', this.callback); }, - "when they do": function(r) { - assert.isTrue(r); + "as staged immediately after its verified": function (r) { + assert.strictEqual(r, false); } }, - "is false": { + "an email address is known": { topic: function() { - db.emailsBelongToSameAccount('lloyd@anywhe.re', 'lloyd@somewhe.re', this.callback); + db.emailKnown('lloyd@nowhe.re', this.callback); }, - "when they don't": function(r) { - assert.isFalse(r); + "when it is": function (r) { + assert.strictEqual(r, true); } } - } -}); + }); -// exports.getSyncResponse -suite.addBatch({ - "sync responses": { - "are empty": { + suite.addBatch({ + "adding keys to email": { topic: function() { - db.getSyncResponse('lloyd@nowhe.re', - { - 'lloyd@nowhe.re': 'fakepubkey', - 'lloyd@somewhe.re': 'fakepubkey4' - }, - this.callback); + db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepubkey2', this.callback); }, - "when everything is in sync": function (err, resp) { - assert.isUndefined(err); - assert.isArray(resp.unknown_emails); - assert.isArray(resp.key_refresh); - assert.strictEqual(resp.unknown_emails.length, 0); - assert.strictEqual(resp.key_refresh.length, 0); + "works": function(r) { + assert.isUndefined(r); } - }, - "handles client unknown emails": { + } + }); + + suite.addBatch({ + "adding multiple keys to email": { topic: function() { - db.getSyncResponse('lloyd@nowhe.re', - { - 'lloyd@nowhe.re': 'fakepubkey' - }, - this.callback); + db.addKeyToEmail('lloyd@nowhe.re', 'lloyd@nowhe.re', 'fakepubkey3', this.callback); }, - "by returning them in the key_refresh list": function (err, resp) { - assert.isUndefined(err); - assert.isArray(resp.unknown_emails); - assert.isArray(resp.key_refresh); - assert.strictEqual(resp.unknown_emails.length, 0); - assert.strictEqual(resp.key_refresh.length, 1); - assert.strictEqual(resp.key_refresh[0], 'lloyd@somewhe.re'); + "works too": function(r) { + assert.isUndefined(r); } - }, - "handles server unknown emails": { + } + }); + + suite.addBatch({ + "pubkeysForEmail": { topic: function() { - db.getSyncResponse('lloyd@nowhe.re', - { - 'lloyd@nowhe.re': 'fakepubkey', - 'lloyd@somewhe.re': 'fakepubkey4', - 'lloyd@anywhe.re': 'nofakepubkey', - }, - this.callback); + db.pubkeysForEmail('lloyd@nowhe.re', this.callback); }, - "by returning them in the unknown_emails list": function (err, resp) { - assert.isUndefined(err); - assert.isArray(resp.unknown_emails); - assert.strictEqual(resp.unknown_emails.length, 1); - assert.strictEqual(resp.unknown_emails[0], 'lloyd@anywhe.re'); - assert.isArray(resp.key_refresh); - assert.strictEqual(resp.key_refresh.length, 0); + "returns all public keys properly": function(r) { + assert.isArray(r); + assert.strictEqual(r.length, 3); } - }, - "handles server unknown keys": { + } + }); + + suite.addBatch({ + "checkAuth returns": { topic: function() { - db.getSyncResponse('lloyd@nowhe.re', - { - 'lloyd@nowhe.re': 'fakepubkeyINVALID', - 'lloyd@somewhe.re': 'fakepubkey4' - }, - this.callback); + db.checkAuth('lloyd@nowhe.re', this.callback); }, - "by returning them in the key_refresh list": function (err, resp) { - assert.isUndefined(err); - assert.isArray(resp.unknown_emails); - assert.strictEqual(resp.unknown_emails.length, 0); - assert.isArray(resp.key_refresh); - assert.strictEqual(resp.key_refresh.length, 1); - assert.strictEqual(resp.key_refresh[0], 'lloyd@nowhe.re'); + "the correct password": function(r) { + assert.strictEqual(r, "fakepasswordhash"); } - }, - "handle more than one case at a time": { + } + }); + + suite.addBatch({ + "staging an email": { topic: function() { - db.getSyncResponse('lloyd@nowhe.re', - { - 'lloyd@somewhe.re': 'fakepubkeyINVALID', - 'lloyd@anywhe.re': 'notreally' - }, - this.callback); + db.stageEmail('lloyd@nowhe.re', 'lloyd@somewhe.re', 'fakepubkey4', this.callback); }, - "when everything is outta sync": function (err, resp) { - assert.isUndefined(err); - assert.isArray(resp.unknown_emails); - assert.strictEqual(resp.unknown_emails.length, 1); - assert.strictEqual(resp.unknown_emails[0], 'lloyd@anywhe.re'); + "yields a valid secret": function(secret) { + assert.isString(secret); + assert.strictEqual(secret.length, 48); + }, + "then": { + topic: function(secret) { + var cb = this.callback; + db.isStaged('lloyd@somewhe.re', function(r) { cb(secret, r); }); + }, + "makes it visible via isStaged": function(sekret, r) { assert.isTrue(r); }, + "and lets you verify it": { + topic: function(secret, r) { + db.gotVerificationSecret(secret, this.callback); + }, + "successfully": function(r) { + assert.isUndefined(r); + }, + "and knownEmail": { + topic: function() { db.emailKnown('lloyd@somewhe.re', this.callback); }, + "returns true": function(r) { assert.isTrue(r); } + }, + "and isStaged": { + topic: function() { db.isStaged('lloyd@somewhe.re', this.callback); }, + "returns false": function(r) { assert.isFalse(r); } + } + } + } + } + }); - assert.isArray(resp.key_refresh); - assert.strictEqual(resp.key_refresh.length, 2); - assert.strictEqual(resp.key_refresh[0], 'lloyd@nowhe.re'); - assert.strictEqual(resp.key_refresh[1], 'lloyd@somewhe.re'); + // exports.emailsBelongToSameAccount + suite.addBatch({ + "emails do belong to the same account": { + "is true": { + topic: function() { + db.emailsBelongToSameAccount('lloyd@nowhe.re', 'lloyd@somewhe.re', this.callback); + }, + "when they do": function(r) { + assert.isTrue(r); + } + }, + "is false": { + topic: function() { + db.emailsBelongToSameAccount('lloyd@anywhe.re', 'lloyd@somewhe.re', this.callback); + }, + "when they don't": function(r) { + assert.isFalse(r); + } } } - } -}); + }); -suite.addBatch({ - "removing an existing email": { - topic: function() { - db.removeEmail("lloyd@somewhe.re", "lloyd@nowhe.re", this.callback); - }, - "returns no error": function(r) { - assert.isUndefined(r); - }, - "causes emailKnown": { - topic: function() { - db.emailKnown('lloyd@nowhe.re', this.callback); + // exports.getSyncResponse + suite.addBatch({ + "sync responses": { + "are empty": { + topic: function() { + db.getSyncResponse('lloyd@nowhe.re', + { + 'lloyd@nowhe.re': 'fakepubkey', + 'lloyd@somewhe.re': 'fakepubkey4' + }, + this.callback); + }, + "when everything is in sync": function (err, resp) { + assert.isUndefined(err); + assert.isArray(resp.unknown_emails); + assert.isArray(resp.key_refresh); + assert.strictEqual(resp.unknown_emails.length, 0); + assert.strictEqual(resp.key_refresh.length, 0); + } }, - "to return false": function (r) { - assert.strictEqual(r, false); + "handles client unknown emails": { + topic: function() { + db.getSyncResponse('lloyd@nowhe.re', + { + 'lloyd@nowhe.re': 'fakepubkey' + }, + this.callback); + }, + "by returning them in the key_refresh list": function (err, resp) { + assert.isUndefined(err); + assert.isArray(resp.unknown_emails); + assert.isArray(resp.key_refresh); + assert.strictEqual(resp.unknown_emails.length, 0); + assert.strictEqual(resp.key_refresh.length, 1); + assert.strictEqual(resp.key_refresh[0], 'lloyd@somewhe.re'); + } + }, + "handles server unknown emails": { + topic: function() { + db.getSyncResponse('lloyd@nowhe.re', + { + 'lloyd@nowhe.re': 'fakepubkey', + 'lloyd@somewhe.re': 'fakepubkey4', + 'lloyd@anywhe.re': 'nofakepubkey', + }, + this.callback); + }, + "by returning them in the unknown_emails list": function (err, resp) { + assert.isUndefined(err); + assert.isArray(resp.unknown_emails); + assert.strictEqual(resp.unknown_emails.length, 1); + assert.strictEqual(resp.unknown_emails[0], 'lloyd@anywhe.re'); + assert.isArray(resp.key_refresh); + assert.strictEqual(resp.key_refresh.length, 0); + } + }, + "handles server unknown keys": { + topic: function() { + db.getSyncResponse('lloyd@nowhe.re', + { + 'lloyd@nowhe.re': 'fakepubkeyINVALID', + 'lloyd@somewhe.re': 'fakepubkey4' + }, + this.callback); + }, + "by returning them in the key_refresh list": function (err, resp) { + assert.isUndefined(err); + assert.isArray(resp.unknown_emails); + assert.strictEqual(resp.unknown_emails.length, 0); + assert.isArray(resp.key_refresh); + assert.strictEqual(resp.key_refresh.length, 1); + assert.strictEqual(resp.key_refresh[0], 'lloyd@nowhe.re'); + } + }, + "handle more than one case at a time": { + topic: function() { + db.getSyncResponse('lloyd@nowhe.re', + { + 'lloyd@somewhe.re': 'fakepubkeyINVALID', + 'lloyd@anywhe.re': 'notreally' + }, + this.callback); + }, + "when everything is outta sync": function (err, resp) { + assert.isUndefined(err); + assert.isArray(resp.unknown_emails); + assert.strictEqual(resp.unknown_emails.length, 1); + assert.strictEqual(resp.unknown_emails[0], 'lloyd@anywhe.re'); + + assert.isArray(resp.key_refresh); + assert.strictEqual(resp.key_refresh.length, 2); + assert.strictEqual(resp.key_refresh[0], 'lloyd@nowhe.re'); + assert.strictEqual(resp.key_refresh[1], 'lloyd@somewhe.re'); + } } } - } -}); + }); -suite.addBatch({ - "canceling an account": { - topic: function() { - db.cancelAccount("lloyd@somewhe.re", this.callback); - }, - "returns no error": function(r) { - assert.isUndefined(r); - }, - "causes emailKnown": { + suite.addBatch({ + "removing an existing email": { topic: function() { - db.emailKnown('lloyd@somewhe.re', this.callback); + db.removeEmail("lloyd@somewhe.re", "lloyd@nowhe.re", this.callback); }, - "to return false": function (r) { - assert.strictEqual(r, false); + "returns no error": function(r) { + assert.isUndefined(r); + }, + "causes emailKnown": { + topic: function() { + db.emailKnown('lloyd@nowhe.re', this.callback); + }, + "to return false": function (r) { + assert.strictEqual(r, false); + } } } - } -}); + }); -// exports.cancelAccount -// exports.removeEmail + suite.addBatch({ + "canceling an account": { + topic: function() { + db.cancelAccount("lloyd@somewhe.re", this.callback); + }, + "returns no error": function(r) { + assert.isUndefined(r); + }, + "causes emailKnown": { + topic: function() { + db.emailKnown('lloyd@somewhe.re', this.callback); + }, + "to return false": function (r) { + assert.strictEqual(r, false); + } + } + } + }); -suite.addBatch({ - "remove the database file": { - topic: function() { - fs.unlink(db.dbPath, this.callback); - }, - "and unlink should not error": function(err) { - assert.isNull(err); - }, - "and the file": { + suite.addBatch({ + "closing the database": { topic: function() { - path.exists(db.dbPath, this.callback); + db.close(this.callback); }, - "should be missing": function(r) { - assert.isFalse(r); + "should work": function(err) { + assert.isUndefined(err); } } + }); + + if (driver !== 'mysql') { + suite.addBatch({ + "remove the database file": { + topic: function() { + fs.unlink(dbPath, this.callback); + }, + "and unlink should not error": function(err) { + assert.isNull(err); + }, + "and the file": { + topic: function() { + path.exists(dbPath, this.callback); + }, + "should be missing": function(r) { + assert.isFalse(r); + } + } + } + }); + } +} + +// test all available drivers +files = fs.readdirSync(path.join(__dirname, "..", "lib")); + +files.forEach(function(f) { + var m = /^db_(.+)\.js$/.exec(f); + if (m) { + addTestsForDriver(m[1]); } }); // run or export the suite. if (process.argv[1] === __filename) suite.run(); else suite.export(module); + diff --git a/browserid/tests/forgotten-email-test.js b/browserid/tests/forgotten-email-test.js index 1a7d015476b3ec4076256c9fe4f3ace339a597f5..0c67fc92b39d3021a747ed5d9f768bbff77946bf 100755 --- a/browserid/tests/forgotten-email-test.js +++ b/browserid/tests/forgotten-email-test.js @@ -1,13 +1,51 @@ #!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const assert = require('assert'), - vows = require('vows'), - start_stop = require('./lib/start-stop.js'), - wsapi = require('./lib/wsapi.js'), - interceptor = require('./lib/email-interceptor.js'); +vows = require('vows'), +start_stop = require('./lib/start-stop.js'), +wsapi = require('./lib/wsapi.js'), +interceptor = require('./lib/email-interceptor.js'); var suite = vows.describe('forgotten-email'); +// disable vows (often flakey?) async error behavior +suite.options.error = false; + start_stop.addStartupBatches(suite); // ever time a new token is sent out, let's update the global diff --git a/browserid/tests/lib/email-interceptor.js b/browserid/tests/lib/email-interceptor.js index 3ac9c7212ae35f6b054f5ff25ba96abc33b3b8c9..ac255fbb12455dce2a3e35dc7d76cb31f5680d58 100644 --- a/browserid/tests/lib/email-interceptor.js +++ b/browserid/tests/lib/email-interceptor.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // a tiny abstraction which kludges its way into nodemailer to intercept // outbound emails for testing diff --git a/browserid/tests/lib/start-stop.js b/browserid/tests/lib/start-stop.js index 33892996f398707fa5c374a7bccd93ded08ac0fe..636c042a4c8efb27542813eeb1b26691ea6dfcf8 100644 --- a/browserid/tests/lib/start-stop.js +++ b/browserid/tests/lib/start-stop.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const assert = require('assert'), fs = require('fs'), path = require('path'), diff --git a/browserid/tests/lib/wsapi.js b/browserid/tests/lib/wsapi.js index dc3a9c93c2cdc720ddab5f156984b66af2f0fb15..cd2f08e683093e4b1a49b60c3812e069f009071d 100644 --- a/browserid/tests/lib/wsapi.js +++ b/browserid/tests/lib/wsapi.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const http = require('http'), querystring = require('querystring'); diff --git a/browserid/tests/registration-status-wsapi-test.js b/browserid/tests/registration-status-wsapi-test.js index 1d45c2f8d2a77985af296894640123c414d8fe4f..da482e9184483981b7fdf9d11e7be6e45e2da287 100755 --- a/browserid/tests/registration-status-wsapi-test.js +++ b/browserid/tests/registration-status-wsapi-test.js @@ -1,5 +1,40 @@ #!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const assert = require('assert'), vows = require('vows'), start_stop = require('./lib/start-stop.js'), diff --git a/browserid/views/users.ejs b/browserid/views/users.ejs index dc0a4f6d09346cdf1446f0873d91beefe986b9c7..97b25729dd23968bffd40153b97c3f1000f57e48 100644 --- a/browserid/views/users.ejs +++ b/browserid/views/users.ejs @@ -3,6 +3,6 @@ As a user of BrowserID, you confirm your email addresses once. Then, you can sign into any web site that supports BrowserID with just two clicks. </p> - <center><iframe width="480" height="390" src="http://www.youtube.com/embed/l0t9yDLAmFo" frameborder="0" allowfullscreen></iframe></center> + <center><iframe width="480" height="390" src="https://www.youtube.com/embed/l0t9yDLAmFo" frameborder="0" allowfullscreen></iframe></center> </div> diff --git a/libs/configuration.js b/libs/configuration.js index b3cfa84f70ec3f3773e7f0e9503d555ae30db65d..ecddccb7be0aa2f3e4767d3267531b8eed0c0fc4 100644 --- a/libs/configuration.js +++ b/libs/configuration.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + /* * An abstraction which contains various pre-set deployment * environments and adjusts runtime configuration appropriate for @@ -7,7 +42,9 @@ * exports.configure(app); */ -const substitution = require('./substitute.js'); +const +substitution = require('./substitute.js'), +path = require('path'); var g_config = { }; @@ -19,31 +56,45 @@ exports.get = function(val) { return g_config[val]; } +var defaultHostedDatabaseConfig = { + driver: "mysql", + user: 'browserid', + password: 'browserid' +}; + // various deployment configurations const g_configs = { production: { hostname: 'browserid.org', port: '443', scheme: 'https', - use_minified_resources: true + use_minified_resources: true, + log_path: '/home/browserid/var/', + database: defaultHostedDatabaseConfig }, development: { hostname: 'dev.diresworb.org', port: '443', scheme: 'https', - use_minified_resources: true + use_minified_resources: true, + log_path: '/home/browserid/var/', + database: defaultHostedDatabaseConfig }, beta: { hostname: 'diresworb.org', port: '443', scheme: 'https', - use_minified_resources: true + use_minified_resources: true, + log_path: '/home/browserid/var/', + database: defaultHostedDatabaseConfig }, local: { hostname: '127.0.0.1', port: '10002', scheme: 'http', - use_minified_resources: false + use_minified_resources: false, + log_path: path.join(__dirname, "..", "var", "logs"), + database: { driver: "json" } } }; diff --git a/libs/logging.js b/libs/logging.js new file mode 100644 index 0000000000000000000000000000000000000000..0d4c3422d27fe84732274aad15652f1d75025a4f --- /dev/null +++ b/libs/logging.js @@ -0,0 +1,101 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const +winston = require("winston"), +configuration = require("./configuration"), +path = require('path'), +fs = require('fs'); + +// go through the configuration and determine log location +// for now we only log to one place +// FIXME: separate logs depending on purpose? + +var log_path = configuration.get('log_path'); +var LOGGERS = []; + +// simple inline function for creation of dirs +function mkdir_p(p) { + if (!path.existsSync(p)) { + mkdir_p(path.dirname(p)); + console.log("mkdir", p); + fs.mkdirSync(p, "0755"); + } +} + +function setupLogger(category) { + if (!log_path) + return console.log("no log path! Not logging!"); + else + mkdir_p(log_path); + + + // don't create the logger if it already exists + if (LOGGERS[category]) + return; + + var filename = path.join(log_path, category + "-log.txt"); + + LOGGERS[category] = new (winston.Logger)({ + transports: [new (winston.transports.File)({filename: filename})] + }); +} + +// entry is an object that will get JSON'ified +exports.log = function(category, entry) { + // entry must have at least a type + if (!entry.type) + throw new Error("every log entry needs a type"); + + // setup the logger if need be + setupLogger(category); + + // timestamp + entry.at = new Date().toUTCString(); + + // if no logger, go to console (FIXME: do we really want to log to console?) + LOGGERS[category].info(JSON.stringify(entry)); +}; + +// utility function to log a bunch of stuff at user entry point +exports.userEntry = function(category, req) { + exports.log(category, { + type: 'signin', + browser: req.headers['user-agent'], + rp: req.headers['referer'], + // IP address (this probably needs to be replaced with the X-forwarded-for value + ip: req.connection.remoteAddress + }); +}; \ No newline at end of file diff --git a/libs/substitute.js b/libs/substitute.js index ab04aeec1e4f2ff6a1bb9912b044435cb9583dd2..2c4c526aedbbaac25231c855ebddd27fcd26287b 100644 --- a/libs/substitute.js +++ b/libs/substitute.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // return a function that is substitution middleware, capable // of being installed to perform textual replacement on // all server output diff --git a/package.json b/package.json index 78fdad42fca3a034200031b76e68b1a78cbccad4..4691170022a0f6cfdb923871eabe62af751055ca 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ , "dependencies": { "express": "2.4.3" , "xml2js": "0.1.5" - , "sqlite": "1.0.3" , "nodemailer": "0.1.18" , "mustache": "0.3.1-dev" , "cookie-sessions": "0.0.2" @@ -15,5 +14,9 @@ , "temp": "0.2.0" , "express-csrf": "0.3.2" , "uglify-js": "1.0.6" + , "JSONSelect": "0.2.1" + , "winston" : "0.3.3" + , "connect-cookie-session" : "0.0.1" + , "mysql" : "0.9.1" } -} \ No newline at end of file +} diff --git a/run.js b/run.js index c9e78c4050682ad9cbd1e32674099f9a77810e0a..d710da851074ff0fb3c2d308f8889e182520fe81 100755 --- a/run.js +++ b/run.js @@ -1,5 +1,40 @@ #!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // a little node webserver designed to run the unit tests herein var sys = require("sys"), diff --git a/scripts/branch_train.sh b/scripts/branch_train.sh new file mode 100755 index 0000000000000000000000000000000000000000..fe73cf673fa3ea34fc8764f80add229ef1528fcb --- /dev/null +++ b/scripts/branch_train.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +git branch train-$(date +'%Y.%m.%d') dev + diff --git a/test.sh b/test.sh new file mode 100755 index 0000000000000000000000000000000000000000..a0ef1563a8e8f5556edc3d85fce2c29c7936278f --- /dev/null +++ b/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +VOWS=`which vows 2> /dev/null` +if [ ! -x "$VOWS" ]; then + echo "vows not found in your path. try: npm install -g vows" + exit 1 +fi + +for file in browserid/tests/*.js ; do + vows $file + if [[ $? != 0 ]] ; then + exit 1 + fi +done diff --git a/verifier/app.js b/verifier/app.js index 2503a31be9d9a96453519c08f6a5a04623e69773..9b8f8e1989ba94e9bbb2187d89e67875bb028d87 100644 --- a/verifier/app.js +++ b/verifier/app.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const path = require('path'), url = require('url'), fs = require('fs'), @@ -5,6 +40,7 @@ const path = require('path'), idassertion = require('./lib/idassertion.js'), jwt = require('./lib/jwt.js'), express = require('express'); + logging = require('../libs/logging.js'); // create the var directory if it doesn't exist var VAR_DIR = path.join(__dirname, "var"); @@ -35,6 +71,13 @@ function doVerify(req, resp, next) { .verify( audience, function(payload) { + // log it! + logging.log('verifier', { + type: 'verify', + result: 'success', + rp: payload.audience + }); + result = { status : "okay", email : payload.email, @@ -45,11 +88,21 @@ function doVerify(req, resp, next) { resp.json(result); }, function(errorObj) { + logging.log('verifier', { + type: 'verify', + result: 'failure', + rp: audience + }); resp.json({ status: "failure", reason: errorObj }); } ); } catch (e) { console.log(e.stack); + logging.log('verifier', { + type: 'verify', + result: 'failure', + rp: audience + }); resp.json({ status: "failure", reason: e.toString() }); } } diff --git a/verifier/lib/httputils.js b/verifier/lib/httputils.js index ef7abf3130a2dcb24e9cf0058a23c1c3a125e43c..aad0bd98983f83731ed9326b2cd23649c6452c6f 100644 --- a/verifier/lib/httputils.js +++ b/verifier/lib/httputils.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + // various little utilities to make crafting boilerplate responses // simple diff --git a/verifier/lib/idassertion.js b/verifier/lib/idassertion.js index 4845f9805c59eabb1ced138cb65d64fd52061aae..0893488a9d55f99c64f14a438aa32e04aae075dd 100644 --- a/verifier/lib/idassertion.js +++ b/verifier/lib/idassertion.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + /* * bug garage: * diff --git a/verifier/lib/jwt.js b/verifier/lib/jwt.js index fdf96f8c54196cb77a26316d833013d3eed2d512..a70d68ec9bc2b77662fe13fd52189d43ebc17059 100644 --- a/verifier/lib/jwt.js +++ b/verifier/lib/jwt.js @@ -1,3 +1,38 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const crypto = require("crypto"); const rsa = require("./rsa.js"); diff --git a/verifier/lib/make_assertion.js b/verifier/lib/make_assertion.js index 54afcdd70069fd4ab2424e7fb0be4dcf508a7a30..38374a5be99d5295471f692f54117ac79cc0d1b7 100644 --- a/verifier/lib/make_assertion.js +++ b/verifier/lib/make_assertion.js @@ -1,5 +1,40 @@ #!/usr/local/bin/node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const fs = require("fs"); const jwt = require("./jwt.js"); const idassertion = require("./idassertion.js"); diff --git a/verifier/run.js b/verifier/run.js index 34adb7f8e4bbd9b2765a0ed395c545166a883b30..1ab4c936e1273f6f92016975af1f1283eff166ce 100755 --- a/verifier/run.js +++ b/verifier/run.js @@ -1,5 +1,40 @@ #!/usr/bin/env node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + var sys = require("sys"), path = require("path"), fs = require("fs"), diff --git a/verifier/tests/run.js b/verifier/tests/run.js index c7c457c5c52b87f9340ac049ddd54b035a053ade..8e6d85ab85c31406b4310e0edabfa5a92960c66b 100755 --- a/verifier/tests/run.js +++ b/verifier/tests/run.js @@ -1,5 +1,40 @@ #!/usr/local/bin/node +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla BrowserID. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + const jwt = require("../lib/jwt.js"); const idassertion = require("../lib/idassertion.js"); const vows = require('vows');