Created
April 13, 2012 18:22
-
-
Save jonmarkgo/2378931 to your computer and use it in GitHub Desktop.
Two-Factor Authentication with Node.js and Twilio
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var client = new TwilioClient('ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'yourwebsite.com'); | |
var phone = client.getPhoneNumber('+18881234567'); | |
app.configure(function () { | |
app.set('view engine', 'jade'); | |
app.set('view options', {layout: false}); | |
app.use(express.cookieParser()); | |
app.use("/bootstrap", express['static'](__dirname + '/bootstrap')); | |
app.use(express.session({ | |
secret: 'secret', | |
key: 'express.sid', | |
store: store = new MemoryStore() | |
})); | |
}); | |
app.get('/', function (req, res) { | |
res.render('index', {username: req.session.username, phonenumber: req.session.phonenumber}); | |
}); | |
app.listen(8080); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
socket.on('set username', function (val) { | |
sess.reload(function () { | |
sess.username = val; | |
sess.touch().save(); | |
}); | |
}); | |
socket.on('set password', function (val) { | |
sess.reload(function () { | |
sess.password = val; | |
sess.touch().save(); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
socket.on('init phone', function (val) { | |
sess.reload(function () { | |
sess.phonenumber = val; | |
var codelength = 4; //# of digits in the verification code | |
sess.verify = Math.floor(Math.random() * (Math.pow(10, (codelength - 1)) * 9)) + Math.pow(10, (codelength - 1)); | |
sess.touch().save(); | |
socket.emit('newcode', sess.verify); | |
phone.setup(function () { | |
phone.makeCall(val, null, function (call) { | |
call.on('answered', function (reqParams, res) { | |
console.log('Call answered'); | |
var intro = new Twiml.Say('Hello, ' + sess.username + '. Please enter your ' + String(sess.verify).length + ' digit verification code!'); | |
res.append(getDigit(0, sess.verify).append(intro)); | |
res.send(); | |
}); | |
call.on('ended', function (reqParams) { | |
console.log('Call ended'); | |
}); | |
}); | |
}); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getDigit(num, verify) { | |
var getDigits = new Twiml.Gather(null, {numDigits: 1}); | |
getDigits.on('gathered', function (reqParams, resp) { | |
if (reqParams.Digits === String(verify).charAt(num)) { | |
socket.emit('correct code', num); | |
if (num < (String(verify).length - 1)) { | |
resp.append(getDigit(num + 1, verify)); | |
} else { | |
socket.emit('verified', 1); | |
resp.append(new Twiml.Say('Thank you, good bye!')); | |
} | |
} else { | |
resp.append(new Twiml.Say('You have entered the wrong code, please try logging in again.')).append(new Twiml.Hangup()); | |
socket.emit('wrong code', num); | |
} | |
resp.send(); | |
}); | |
return getDigits; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jslint unparam: true, node: true, sloppy: true, nomen: true, maxerr: 50, indent: 2 */ | |
var io = require('socket.io'), express = require('express'), util = require('util'), app = express.createServer(), connect = require('express/node_modules/connect'), parseCookie = connect.utils.parseCookie, MemoryStore = connect.middleware.session.MemoryStore, store, TwilioClient = require('twilio').Client, Twiml = require('twilio').Twiml; | |
var client = new TwilioClient('ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'yourwebsite.com'); //Enter your credentials and hostname here | |
var phone = client.getPhoneNumber('+18881234567'); //Enter your outgoing phone # here | |
app.configure(function () { | |
app.set('view engine', 'jade'); | |
app.set('view options', {layout: false}); | |
app.use(express.cookieParser()); | |
app.use("/bootstrap", express['static'](__dirname + '/bootstrap')); | |
app.use(express.session({ | |
secret: 'secret', | |
key: 'express.sid', | |
store: store = new MemoryStore() | |
})); | |
}); | |
app.get('/', function (req, res) { | |
res.render('index', {username: req.session.username, phonenumber: req.session.phonenumber}); | |
}); | |
app.listen(8080); | |
io.listen(app).set('authorization', function (data, accept) { | |
if (!data.headers.cookie) { | |
return accept('No cookie transmitted.', false); | |
} | |
data.cookie = parseCookie(data.headers.cookie); | |
data.sessionID = data.cookie['express.sid']; | |
store.load(data.sessionID, function (err, session) { | |
if (err || !session) { | |
return accept('Error', false); | |
} | |
data.session = session; | |
return accept(null, true); | |
}); | |
}).sockets.on('connection', function (socket) { | |
var sess = socket.handshake.session; | |
socket.log.info('a socket with sessionID', socket.handshake.sessionID, 'connected'); | |
socket.on('set username', function (val) { | |
sess.reload(function () { | |
sess.username = val; | |
sess.touch().save(); | |
}); | |
}); | |
socket.on('set password', function (val) { | |
sess.reload(function () { | |
sess.password = val; | |
sess.touch().save(); | |
}); | |
}); | |
function getDigit(num, verify) { | |
var getDigits = new Twiml.Gather(null, {numDigits: 1}); | |
getDigits.on('gathered', function (reqParams, resp) { | |
if (reqParams.Digits === String(verify).charAt(num)) { | |
socket.emit('correct code', num); | |
if (num < (String(verify).length - 1)) { | |
resp.append(getDigit(num + 1, verify)); | |
} else { | |
socket.emit('verified', 1); | |
resp.append(new Twiml.Say('Thank you, good bye!')); | |
} | |
} else { | |
resp.append(new Twiml.Say('You have entered the wrong code, please try logging in again.')).append(new Twiml.Hangup()); | |
socket.emit('wrong code', num); | |
} | |
resp.send(); | |
}); | |
return getDigits; | |
} | |
socket.on('init phone', function (val) { | |
sess.reload(function () { | |
sess.phonenumber = val; | |
var codelength = 4; //# of digits in the verification code | |
sess.verify = Math.floor(Math.random() * (Math.pow(10, (codelength - 1)) * 9)) + Math.pow(10, (codelength - 1)); | |
sess.touch().save(); | |
socket.emit('newcode', sess.verify); | |
phone.setup(function () { | |
phone.makeCall(val, null, function (call) { | |
call.on('answered', function (reqParams, res) { | |
console.log('Call answered'); | |
var intro = new Twiml.Say('Hello, ' + sess.username + '. Please enter your ' + String(sess.verify).length + ' digit verification code!'); | |
res.append(getDigit(0, sess.verify).append(intro)); | |
res.send(); | |
}); | |
call.on('ended', function (reqParams) { | |
console.log('Call ended'); | |
}); | |
}); | |
}); | |
}); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
loginform.submit(function (e) { | |
e.preventDefault(); | |
socket.emit('set username', username.val()); | |
socket.emit('set password', password.val()); | |
socket.emit('init phone', phonenumber.val()); | |
}).focus(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
socket.on('newcode', function (val) { | |
$("#verify").show(); | |
$("#verify").removeClass("alert-error"); | |
$("#verify").removeClass("alert-success"); | |
$("#verify").addClass("alert-info"); | |
$("#verify").html('<h1>Verification Code:</h1><br><div id="code"></div><br>'); | |
for(var i =0; i < String(val).length; i++) | |
{ | |
$("#code").append('<span id="code'+i+'" class="badge" style="font-size:50px;">'+String(val).charAt(i)+'</span>'); | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
socket.on('wrong code', function (val) { | |
$("#verify").removeClass("alert-info"); | |
$("#verify").addClass("alert-error"); | |
$("#code" + val).removeClass("badge-info"); | |
$("#code" + val).addClass("badge-error"); | |
$("#verify h1").html('Incorrect Code, Try Again!'); | |
}); | |
socket.on('verified', function (val) { | |
$("#verify").removeClass("alert-info"); | |
$("#verify").removeClass("alert-error"); | |
$("#verify").addClass("alert-success"); | |
$("#verify").html('You have successfully logged in!'); | |
$("#loginform").hide(); | |
$("#nyan").show(); | |
}); | |
socket.on('correct code', function (val) { | |
$("#code" + val).removeClass("badge-info"); | |
$("#code" + val).addClass("badge-success"); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!!! html | |
html | |
head | |
title Two-Factor Authentication with Twilio, Node.js, and Socket.io | |
script(src='/socket.io/socket.io.js') | |
script(src='http://code.jquery.com/jquery-latest.js') | |
link(rel='stylesheet', href='/bootstrap/css/bootstrap.min.css') | |
link(rel='stylesheet', href='/bootstrap/css/bootstrap-responsive.min.css') | |
body | |
div.container | |
h1 Two-Factor Auth Demo | |
div.alert.alert-info#verify | |
h1 Verification Code: | |
br | |
div#code | |
br | |
div.row | |
div.span5 | |
img#nyan(src='/bootstrap/poptart1red1.gif') | |
form.well#loginform | |
fieldset | |
legend Login to Access Secrets | |
div.control-group | |
input#username(placeholder='Username') | |
input#password(type='password',placeholder='Password') | |
input#phonenumber(placeholder='+18881234567') | |
div.form-actions | |
input#submit.btn.btn-primary(type='submit',value='Log In') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!!! html | |
html | |
head | |
title Two-Factor Authentication with Twilio, Node.js, and Socket.io | |
script(src='/socket.io/socket.io.js') | |
script(src='http://code.jquery.com/jquery-latest.js') | |
link(rel='stylesheet', href='/bootstrap/css/bootstrap.min.css') | |
link(rel='stylesheet', href='/bootstrap/css/bootstrap-responsive.min.css') | |
body | |
div.container | |
h1 Two-Factor Auth Demo | |
div.alert.alert-info#verify | |
h1 Verification Code: | |
br | |
div#code | |
br | |
div.row | |
div.span5 | |
img#nyan(src='/bootstrap/poptart1red1.gif') | |
form.well#loginform | |
fieldset | |
legend Login to Access Secrets | |
div.control-group | |
input#username(placeholder='Username') | |
input#password(type='password',placeholder='Password') | |
input#phonenumber(placeholder='+18881234567') | |
div.form-actions | |
input#submit.btn.btn-primary(type='submit',value='Log In') | |
script | |
$(function () { | |
$("#verify").hide(); | |
$("#nyan").hide(); | |
var socket = io.connect() | |
, username = $('#username') | |
, password = $('#password') | |
, phonenumber = $('#phonenumber') | |
, submit = $('#submit') | |
, loginform = $('#loginform'); | |
socket.on('newcode', function (val) { | |
$("#verify").show(); | |
$("#verify").removeClass("alert-error"); | |
$("#verify").removeClass("alert-success"); | |
$("#verify").addClass("alert-info"); | |
$("#verify").html('<h1>Verification Code:</h1><br><div id="code"></div><br>'); | |
for(var i =0; i < String(val).length; i++) | |
{ | |
$("#code").append('<span id="code'+i+'" class="badge" style="font-size:50px;">'+String(val).charAt(i)+'</span>'); | |
} | |
}); | |
socket.on('wrong code', function (val) { | |
$("#verify").removeClass("alert-info"); | |
$("#verify").addClass("alert-error"); | |
$("#code" + val).removeClass("badge-info"); | |
$("#code" + val).addClass("badge-error"); | |
$("#verify h1").html('Incorrect Code, Try Again!'); | |
}); | |
socket.on('verified', function (val) { | |
$("#verify").removeClass("alert-info"); | |
$("#verify").removeClass("alert-error"); | |
$("#verify").addClass("alert-success"); | |
$("#verify").html('You have successfully logged in!'); | |
$("#loginform").hide(); | |
$("#nyan").show(); | |
}); | |
socket.on('correct code', function (val) { | |
$("#code" + val).removeClass("badge-info"); | |
$("#code" + val).addClass("badge-success"); | |
}); | |
loginform.submit(function (e) { | |
e.preventDefault(); | |
socket.emit('set username', username.val()); | |
socket.emit('set password', password.val()); | |
socket.emit('init phone', phonenumber.val()); | |
}).focus(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment