diff --git a/.gitignore b/.gitignore index f4e3dcc..fb280fe 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ lib-cov *.pid *.gz +db pids logs results diff --git a/config.js b/config.js new file mode 100644 index 0000000..662be52 --- /dev/null +++ b/config.js @@ -0,0 +1,16 @@ +var join = require('path').join + , name = 'squatconf' + , cwd = process.cwd() + +module.exports = require('rc')(name, { + db_opts: { valueEncoding: 'json' } + , db_path: join(cwd, 'db', name) + , port: 8000 + , host: "squatconf.eu" + , email: { + from : "no-reply@squatconf.eu" + , subject : "Hello, everyone is welcome at SquatConf.." + , bodyText : "Please verify that you wish to signup by following this link\n%link%\nYou can ignore this message if you DID NOT request to signup at our website\nhttp://squatconf.eu\n\nThe next event is in Paris, we hope to see you there !!\n\nKind regards from the team,\nSquatConf Paris 2014" + } +}) + diff --git a/config.json b/config.json deleted file mode 100644 index 5f8ced6..0000000 --- a/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "db": { - "path": "" - }, - - "email": { - "from" : "no-reply@squatconf.eu" - , "subject" : "Hello, everyone is welcome at SquatConf.." - , "bodyText": "Please verify that you wish to signup by following this link\n%link%\nYou can ignore this message if you DID NOT request to signup at our website\nhttp://squatconf.eu\n\nThe next event is in Paris, we hope to see you there !!\n\nKind regards from the team,\nSquatConf Paris 2014" - - } -} - diff --git a/html/verified.html b/html/verified.html new file mode 100644 index 0000000..1af7948 --- /dev/null +++ b/html/verified.html @@ -0,0 +1,77 @@ + + + + + SquatConf.386 + + + + + + + + + + +
+
+ +
+ +
+ + + +
+ +
+

You're verified

+

+

Thanks for completing our signup process

+
+ Go back +
+
+
+
+ + + + + diff --git a/package.json b/package.json index aee6ee8..2aee1ff 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "squatconf-web", - "version": "0.3.0", + "version": "0.4.0", "description": "website for the squatConf conference", "main": "server.js", "scripts": { "start": "echo -n 'building.. '; npm run build && node server.js", - "build": "browserify src/email.js -o html/assets/js/email.js", + "build": "browserify src/email-client.js -o html/assets/js/email.js", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -25,7 +25,13 @@ "dependencies": { "browserify": "^5.11.2", "domready": "^1.0.7", + "level": "^0.18.0", + "ecstatic": "^0.5.4", "nodemailer": "^1.3.0", - "valid-email": "0.0.1" + "rc": "^0.5.1", + "stack": "^0.1.0", + "tiny-route": "^2.1.1", + "valid-email": "0.0.1", + "xss-escape": "0.0.5" } } diff --git a/server.js b/server.js index b20f6dd..425747a 100644 --- a/server.js +++ b/server.js @@ -1,72 +1,37 @@ #!/usr/bin/env node -var nodemailer = require('nodemailer') - , transporter = nodemailer.createTransport() - , server = require('http').createServer(handler) - , email = require('./config.json').email - , rn = require('./src/rng') - , fs = require('fs') - , re = new RegExp('\.js$', 'i') - , port = process.env.PORT || /*80*/ 8000 - -function handler(req, res) { - - // process incoming requests. - if (req.url == '/') req.url = '/index.html' - else if (re.test(req.url)) - res.setHeader('Content-Type', 'application/javascript') - - if (/^\/confirm\?/.test(req.url)) { - - // @TODO - // compare submitted token with the token stored in our database. - - res.statusCode = 302 - res.setHeader('Location', '/') - return res.end() - } - - if (/^\/email\?/.test(req.url)) { - var params = require('url').parse(req.url, true) - if (params && params.query.email) { - - /* - var to_addr = params.query.email // @NOTE: - // Q: do we trust the user input ? - // A: FUCK NO !! - , url = 'http://squatconf.eu/confirm' - , link = url +'?email='+ to_addr +'&token='+ rn() +'\n\n' - - var opts = { - from : email.from - , to : to_addr - , subject: email.subject - , text : email.bodyText.replace(/\%link\%/, link) - } - - transporter.sendMail(opts, function(err, data) { - if (err) return console.error('email problem !', err) - console.log('email sent', data) - }) - */ - - console.log(' got email:', params.query) - } - res.statusCode = 302 - res.setHeader('Location', '/') - return res.end() - } - - // serve static assets - var rs = fs.createReadStream(__dirname +'/html'+ req.url) - rs.pipe(res) -} +var fs = require('fs') + , http = require('http') + , stack = require('stack') + , route = require('tiny-route') + , assets = require('ecstatic') + , join = require('path').join + , config = require('./config') + , db = require('level')(config.db_path, config.db_opts) + , port = process.env.PORT || config.port + +// create the level db folder if it does not exists +if(!fs.existsSync('./db/squatconf')){ + fs.mkdirSync('./db/squatconf', 0766, function(err){ + if(err){ + console.log(err); + } + }); + } + +var app = stack( + route('/email', require('./src/email-submit')(db)) + , route('/confirm', require('./src/email-confirm')(db)) + , assets(join(__dirname, 'html')) +) process.on('uncaughtException', function (err) { console.error('Error at:', new Date) console.error(err.stack) }) -server.listen(port) -console.error('['+ process.pid +'] server started on port '+ port) -console.error('(use ctrl+c to stop server)') +http.createServer(app).listen(port, function() { + console.log('['+ process.pid +'] server started on port '+ port) + console.log('(use Ctrl+c to stop the server)') +}) + diff --git a/src/email.js b/src/email-client.js similarity index 100% rename from src/email.js rename to src/email-client.js diff --git a/src/email-confirm.js b/src/email-confirm.js new file mode 100644 index 0000000..a2e5df9 --- /dev/null +++ b/src/email-confirm.js @@ -0,0 +1,39 @@ +var sanitize = require('xss-escape') + , ip = require('./ip-trace') + +module.exports = function(db) { + return function (req, res, next) { + req.resume() + + var params = require('url').parse(req.url, true) + + if (params && params.query.email && params.query.token) { + //console.log('got token:', params.query) + + var email = sanitize(params.query.email) + , token = sanitize(params.query.token) + + db.get(email, function(err, obj) { + if (err) next(err) + + // db read OK.. + if (obj && obj.token === token) { + obj.verified = true + obj.trace = obj.trace.concat(ip(req)) + + db.put(email, obj, function(err) { + if (err) next(err) + + // db write OK.. + res.statusCode = 302 + res.setHeader('Location', '/verified.html') + return res.end() + }) + } + }) + + if (next) return next() + } + } +} + diff --git a/src/email-submit.js b/src/email-submit.js new file mode 100644 index 0000000..4b45b69 --- /dev/null +++ b/src/email-submit.js @@ -0,0 +1,54 @@ +var sanitize = require('xss-escape') + , rn = require('./rng') + , ip = require('./ip-trace') + , config = require('../config') + +module.exports = function(db) { + return function (req, res, next) { + req.resume() + + var params = require('url').parse(req.url, true) + + if (params && params.query.email) { + console.log('got email:', params.query) + + var obj = {} + , email = sanitize(params.query.email) + + obj.token = rn() + obj.verified = false + obj.events = { paris: params.query.paris ? true : false } + obj.trace = ip(req) + + db.put(email, obj, function(err) { + if (err) next(err) + + // db write OK.. + var nodemailer = require('nodemailer') + , transporter = nodemailer.createTransport() + , url = 'http://squatconf.eu/confirm' + , link = url +'?email='+ email +'&token='+ obj.token +'\n\n' + + var opts = { + from : config.email.from + , to : email + , subject: config.email.subject + , text : config.email.bodyText.replace(/\%link\%/, link) + } + + transporter.sendMail(opts, function(err, data) { + if (err) throw err + // validation email sent + console.log('email sent..', data) + }) + + res.statusCode = 302 + res.setHeader('Location', '/') + return res.end() + }) + } + + if (next) return next() + } +} + diff --git a/src/ip-trace.js b/src/ip-trace.js new file mode 100644 index 0000000..f34bbe0 --- /dev/null +++ b/src/ip-trace.js @@ -0,0 +1,8 @@ +module.exports = function(req) { + if (req.headers['x-forwarded-for']) { + return req.headers['x-forwarded-for'].split(',') + } else { + return [ req.connection.remoteAddress ] + } +} +