Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial commit

  • Loading branch information...
commit 9f624b3500cee5bce06599bbafc2b32cbd0a7ce9 0 parents
@ednapiranha ednapiranha authored
3  .gitignore
@@ -0,0 +1,3 @@
+.DS_Store
+node_modules
+local.json
4 Makefile
@@ -0,0 +1,4 @@
+test:
+ @./node_modules/.bin/mocha
+
+.PHONY: test
25 README.md
@@ -0,0 +1,25 @@
+# Napkin
+
+## Installation instructions
+
+Clone the repository
+
+> git clone git://github.com/mozilla/napkin.git
+
+> curl http://npmjs.org/install.sh | sh
+
+Install node by using brew or through the website http://nodejs.org/#download
+
+> cd napkin
+
+> cp local.json-dist local.json
+
+> npm install
+
+Run the site
+
+> node app.js
+
+## Tests
+
+> make test
13 app.js
@@ -0,0 +1,13 @@
+var express = require('express');
+var configurations = module.exports;
+var app = express.createServer();
+var nconf = require('nconf');
+var settings = require('./settings')(app, configurations, express);
+
+nconf.argv().env().file({ file: 'local.json' });
+
+// routes
+require("./routes")(app);
+require('./routes/auth')(app, nconf);
+
+app.listen(process.env.PORT || nconf.get('port'));
48 lib/authenticate.js
@@ -0,0 +1,48 @@
+var request = require('request');
+
+/* Browser ID authentication
+ * Requires: web request, settings
+ * Returns: A browser Id email if successful
+ */
+exports.verify = function(req, nconf, callback) {
+ var authUrl = nconf.get('authUrl') + '/verify';
+ var siteUrl = nconf.get('domain') + ':' + nconf.get('authPort');
+
+ if (!req.body.bid_assertion) {
+ return false;
+ }
+
+ var qs = {
+ assertion: req.body.bid_assertion,
+ audience: siteUrl
+ };
+
+ var params = {
+ url: authUrl,
+ form: qs
+ };
+
+ request.post(params, function(err, resp, body) {
+ var email = false;
+
+ if (err) {
+ return callback(err);
+ }
+
+ try {
+ var jsonResp = JSON.parse(body);
+ if (jsonResp.status === 'okay') {
+ email = jsonResp.email;
+ } else {
+ // Response status is 'not okay'
+ return callback(jsonResp);
+ }
+ } catch (err) {
+ return callback(err);
+ }
+
+ return callback(null, email);
+ });
+
+ return true;
+};
8 local.json-dist
@@ -0,0 +1,8 @@
+{
+ "domain": "http://localhost",
+ "port": 3000,
+ "authPort": 3000,
+ "authUrl": "https://browserid.org",
+ "session_secret": "secret",
+ "session_cookie": "session_your_cookie_name"
+}
20 package.json
@@ -0,0 +1,20 @@
+{
+ "name": "bid-scaffold",
+ "version": "0.0.1",
+ "private": true,
+ "engines": {
+ "node": ">= 0.6.17",
+ "npm": "1.1.x"
+ },
+ "dependencies": {
+ "client-sessions": "0.0.3",
+ "connect": "1.8.6",
+ "express": "2.5.9",
+ "nock": ">= 0.13.0",
+ "jade": ">= 0.0.1",
+ "mocha": "0.14.1",
+ "request": "2.9.153",
+ "should": ">= 0.0.1",
+ "nconf": "git://github.com/flatiron/nconf.git"
+ }
+}
13 public/javascripts/main.js
@@ -0,0 +1,13 @@
+$(function() {
+ var loginForm = $('form#login-form');
+
+ // Browser ID login
+ loginForm.on('click', '#login', function() {
+ navigator.id.getVerifiedEmail(function(assertion) {
+ if (assertion) {
+ loginForm.find('input[name="bid_assertion"]').val(assertion);
+ loginForm.submit();
+ }
+ });
+ });
+});
48 public/stylesheets/main.css
@@ -0,0 +1,48 @@
+/* http://meyerweb.com/eric/tools/css/reset/
+ v2.0 | 20110126
+ License: none (public domain)
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
21 routes/auth.js
@@ -0,0 +1,21 @@
+var auth = require('../lib/authenticate');
+
+module.exports = function(app, nconf) {
+ // Login
+ app.post('/login', function(req, res) {
+ auth.verify(req, nconf, function(error, email) {
+ if (email) {
+ req.session.email = email;
+ }
+ res.redirect('/');
+ });
+ });
+
+ // Logout
+ app.get('/logout', function(req, res) {
+ if (req.session) {
+ delete req.session.email;
+ }
+ res.redirect('/?logged_out=1', 303);
+ });
+};
7 routes/index.js
@@ -0,0 +1,7 @@
+module.exports = function(app) {
+ app.get('/', function (req, res) {
+ res.render('index', {
+ pageType: 'index'
+ });
+ });
+};
44 settings.js
@@ -0,0 +1,44 @@
+// Module dependencies.
+module.exports = function(app, configurations, express) {
+ var clientSessions = require('client-sessions');
+ var nconf = require('nconf');
+
+ nconf.argv().env().file({ file: 'local.json' });
+
+ // Configuration
+
+ app.configure(function(){
+ app.set('views', __dirname + '/views');
+ app.set('view engine', 'jade');
+ app.set('view options', { layout: false });
+ app.use(express.bodyParser());
+ app.use(express.methodOverride());
+ app.use(express.static(__dirname + '/public'));
+ app.use(clientSessions({
+ cookieName: nconf.get('session_cookie'),
+ secret: nconf.get('session_secret'), // MUST be set
+ // true session duration:
+ // will expire after duration (ms)
+ // from last session.reset() or
+ // initial cookieing.
+ duration: 24 * 60 * 60 * 1000 * 28 // 4 weeks
+ }));
+ app.use(app.router);
+ });
+
+ app.configure('development, test', function(){
+ app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
+ });
+
+ app.configure('production', function(){
+ app.use(express.errorHandler());
+ });
+
+ app.dynamicHelpers({
+ session: function (req, res) {
+ return req.session;
+ }
+ });
+
+ return app;
+};
8 test/local-test.json
@@ -0,0 +1,8 @@
+{
+ "domain": "http://localhost",
+ "port": 3000,
+ "authPort": 3000,
+ "authUrl": "https://browserid.org",
+ "session_secret": "secret",
+ "session_cookie": "session_your_cookie_name"
+}
36 test/test.authenticate.js
@@ -0,0 +1,36 @@
+var auth = require('../lib/authenticate');
+var should = require('should');
+var nock = require('nock');
+var nconf = require('nconf');
+
+nconf.argv().env().file({ file: 'test/local-test.json' });
+
+var authUrl = nconf.get('domain') + '/verify';
+var siteUrl = nconf.get('domain') + ':' + nconf.get('port');
+var qs = { assertion: '1a2b3c', audience: siteUrl };
+
+describe('login', function() {
+ describe('POST /verify', function() {
+ it('logs the user in when they have good credentials', function() {
+ var scope = nock(authUrl).post('', qs).reply(200, { status: 'okay', email: 'test@test.org' });
+
+ var params = {
+ body: { bid_assertion: qs.assertion }
+ };
+
+ var authResp = auth.verify(params, nconf, function(error, email) { });
+ authResp.should.equal(true);
+ });
+
+ it('does not log the user in if they have bad credentials', function() {
+ var scope = nock(authUrl).post('', qs).reply(500, { status: 'invalid' });
+
+ var params = {
+ body: { }
+ };
+
+ var authResp = auth.verify(params, nconf, function(error, email) { });
+ authResp.should.equal(false);
+ });
+ });
+});
7 views/index.jade
@@ -0,0 +1,7 @@
+extend layout
+
+block content
+ p This is the main page
+
+ if session.email
+ p You are logged in!
27 views/layout.jade
@@ -0,0 +1,27 @@
+!!! 5
+html
+ head
+ title This is my site
+ meta(content='width=device-width, height=device-height, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0', name='viewport')
+ meta(content='yes', name='apple-mobile-web-app-capable')
+ meta(content='chrome=1', http-equiv='X-UA-Compatible')
+ link(rel='shortcut icon', href='/images/favicon.png')
+ link(rel='stylesheet', href='/stylesheets/main.css')
+
+ body
+ #header
+ h1 My Site
+
+ if session.email
+ a(href='/logout') Log out
+ else
+ form(method='post', action='/login', id='login-form')
+ a(href='#', id='login') Log in
+ input(type='hidden', name='bid_assertion', value='1')
+
+ block content
+ #footer
+
+ script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js')
+ script(src='https://browserid.org/include.js', type='text/javascript')
+ script(src='/javascripts/main.js')
Please sign in to comment.
Something went wrong with that request. Please try again.