| @@ -0,0 +1,18 @@ | ||
| var wrap = require('co-monk'); | ||
|
|
||
| module.exports = function(db) { | ||
| var matches = wrap(db.get('match')); | ||
|
|
||
| return { | ||
| post: function*() { | ||
| // All fields found @ this.request.body.fields | ||
| // TODO: Defend against mass assignment vulns | ||
| var res = yield matches.insert(this.request.body); | ||
| this.body = res._id; | ||
| }, | ||
| show: function*() { | ||
| var res = yield matches.findById(decodeURI(this.params.id)); | ||
| this.body = res; | ||
| } | ||
| }; | ||
| }; |
| @@ -0,0 +1,58 @@ | ||
| var passport = require('koa-passport'), | ||
| config = require('./config.js'), | ||
| user = { id: 1, username: 'test' }; | ||
|
|
||
| passport.serializeUser(function(user, done) { | ||
| done(null, user.id) | ||
| }); | ||
|
|
||
| passport.deserializeUser(function(id, done) { | ||
| done(null, user) | ||
| }); | ||
|
|
||
| var LocalStrategy = require('passport-local').Strategy; | ||
| passport.use(new LocalStrategy(function(username, password, done) { | ||
| // TODO: retrieve user ... | ||
| console.log('LOGIN', username, password); | ||
| if (username === 'test' && password === 'test') { | ||
| done(null, user); | ||
| } else { | ||
| done(null, false); | ||
| } | ||
| })); | ||
|
|
||
| var FacebookStrategy = require('passport-facebook').Strategy; | ||
| passport.use(new FacebookStrategy({ | ||
| clientID: process.env.FACEBOOK_CLIENT_ID || config.facebook.clientID, | ||
| clientSecret: process.env.FACEBOOK_SECRET || config.facebook.clientSecret, | ||
| callbackURL: process.env.FACEBOOK_CALLBACK_URL || config.facebook.callbackURL | ||
| }, | ||
| function(token, tokenSecret, profile, done) { | ||
| // TODO: retrieve user ... | ||
| done(null, user) | ||
| } | ||
| )); | ||
|
|
||
| var TwitterStrategy = require('passport-twitter').Strategy; | ||
| passport.use(new TwitterStrategy({ | ||
| consumerKey: process.env.TWITTER_CONSUMER_KEY || config.twitter.consumerKey, | ||
| consumerSecret: process.env.TWITTER_CONSUMER_SECRET || config.twitter.consumerSecret, | ||
| callbackURL: process.env.TWITTER_CALLBACK_URL || config.twitter.callbackURL | ||
| }, | ||
| function(token, tokenSecret, profile, done) { | ||
| // TODO: retrieve user ... | ||
| done(null, user) | ||
| } | ||
| )); | ||
|
|
||
| var GoogleStrategy = require('passport-google-auth').Strategy; | ||
| passport.use(new GoogleStrategy({ | ||
| clientId: process.env.GOOGLE_CLIENT_ID || config.google.clientId, | ||
| clientSecret: process.env.GOOGLE_SECRET || config.google.clientSecret, | ||
| callbackURL: process.env.GOOGLE_CALLBACK_URL || config.google.callbackURL | ||
| }, | ||
| function(token, tokenSecret, profile, done) { | ||
| // TODO: retrieve user ... | ||
| done(null, user) | ||
| } | ||
| )); |
| @@ -0,0 +1,3 @@ | ||
| :: Proxy commandlet for invoking gulp with ES6 features enabled in node | ||
| @echo off | ||
| node --harmony node_modules/gulp/bin/gulp.js %* |
| @@ -0,0 +1,84 @@ | ||
| var gulp = require('gulp'), | ||
| ts = require('gulp-typescript'), | ||
| merge = require('merge2'), | ||
| stylus = require('gulp-stylus'), | ||
| nib = require('nib'), | ||
| browserSync = require('browser-sync').create(), | ||
| nodemon = require('gulp-nodemon'), | ||
| mocha = require('gulp-mocha-co'), | ||
| exit = require('gulp-exit'), | ||
| tsProject = ts.createProject({ | ||
| declarationFiles: false, | ||
| target: 'ES5', | ||
| noExternalResolve : true, | ||
| module : 'commonjs', | ||
| typescript: require('typescript') | ||
| }); | ||
|
|
||
|
|
||
| gulp.task('scripts', function() { | ||
| var tsResult = gulp.src(['static/*.ts', 'static/**/*.ts']) | ||
| .pipe(ts(tsProject)); | ||
|
|
||
| return merge([ // Merge the two output streams, so this task is finished when the IO of both operations are done. | ||
| tsResult.dts.pipe(gulp.dest('static')), | ||
| tsResult.js.pipe(gulp.dest('static')) | ||
| ]) | ||
| .pipe(browserSync.stream()); | ||
| }); | ||
|
|
||
| gulp.task('stylus', function() { | ||
| gulp.src(['static/*.styl', 'static/**/*.styl']) | ||
| .pipe(stylus({ use: [nib()] })) | ||
| .pipe(gulp.dest('static/')) | ||
| .pipe(browserSync.stream()); | ||
| }); | ||
|
|
||
|
|
||
| // Development server live-reload | ||
| gulp.task('nodemon', function() { | ||
| nodemon({ | ||
| script: 'server.js', | ||
| watch: ['api/', 'server.js', 'config.js'], | ||
| env: { PORT: 8000 }, | ||
| nodeArgs: ['--harmony'] | ||
| }).on('restart'); | ||
| }); | ||
|
|
||
| // Development client live-reload | ||
| gulp.task('serve', ['stylus', 'scripts'], function() { | ||
| browserSync.init({ | ||
| proxy: "localhost:8000", | ||
| browser: "chrome" | ||
| }); | ||
|
|
||
| gulp.watch(['static/*.styl', 'static/**/*.styl'], ['stylus']); | ||
| gulp.watch(['static/*.ts', 'static/**/*.ts'], ['scripts']); | ||
| gulp.watch(['views/*.jade', 'views/**/*.jade']).on('change', browserSync.reload); | ||
| }); | ||
|
|
||
|
|
||
| // Tests | ||
| gulp.task('mocha', function() { | ||
| process.env.PORT = 8001; | ||
|
|
||
| return gulp.src(['test/*.js', 'test/**/*.js']) | ||
| .pipe(mocha({ | ||
| reporter: 'nyan' | ||
| })); | ||
| }); | ||
|
|
||
| gulp.task('test-once', function() { | ||
| gulp.tasks.mocha.fn().pipe(exit()); | ||
| }); | ||
|
|
||
| //gulpfile.js | ||
| gulp.task('tdd', function() { | ||
| gulp.watch( | ||
| ['server.js', 'config.js', 'api/*.js', 'api/**/*.js', 'test/*.js', 'test/**/*.js'], | ||
| ['mocha'] | ||
| ); | ||
| }); | ||
|
|
||
| gulp.task('default', ['nodemon', 'mocha', 'tdd', 'serve']); | ||
| //gulp.task('default', ['serve']); |
| @@ -1,96 +1,45 @@ | ||
| { | ||
| "name": "ladr", | ||
| "version": "1.0.0", | ||
| "description": "", | ||
| "main": "server.js", | ||
| "scripts": { | ||
| "start": "gulp dev", | ||
| "test": "gulp test-once" | ||
| }, | ||
| "author": "Jon Hall <jon_hall@outlook.com>", | ||
| "license": "ISC", | ||
| "devDependencies": { | ||
| "browser-sync": "^2.7.3", | ||
| "chai": "^2.3.0", | ||
| "co-supertest": "0.0.10", | ||
| "gulp": "^3.8.11", | ||
| "gulp-exit": "0.0.2", | ||
| "gulp-mocha-co": "^0.4.1-co.3", | ||
| "gulp-nodemon": "^2.0.3", | ||
| "gulp-stylus": "^2.0.2", | ||
| "gulp-typescript": "^2.7.5", | ||
| "merge2": "^0.3.5", | ||
| "nib": "^1.1.0", | ||
| "proxyquire": "^1.5.0", | ||
| "supertest": "^1.0.1", | ||
| "typescript": "^1.5.0-beta" | ||
| }, | ||
| "dependencies": { | ||
| "co-monk": "^1.0.0", | ||
| "co-views": "^0.3.0", | ||
| "jade": "^1.9.2", | ||
| "koa": "^0.20.0", | ||
| "koa-body": "^1.2.1", | ||
| "koa-generic-session": "^1.8.0", | ||
| "koa-logger": "^1.2.2", | ||
| "koa-passport": "^1.1.6", | ||
| "koa-router": "^5.0.1", | ||
| "koa-static": "^1.4.9", | ||
| "monk": "^1.0.1", | ||
| "passport-facebook": "^2.0.0", | ||
| "passport-google-auth": "^1.0.0", | ||
| "passport-local": "^1.0.0", | ||
| "passport-twitter": "^1.0.3" | ||
| } | ||
| } |
| @@ -0,0 +1,145 @@ | ||
| var config = require('./config.js'), | ||
| auth = require('./auth.js'), | ||
| koa = require('koa'), | ||
| logger = require('koa-logger'), | ||
| session = require('koa-generic-session'), | ||
| passport = require('koa-passport'), | ||
| Router = require('koa-router'), | ||
| koaBody = require('koa-body')({ formiddable: { multiples: false } }), | ||
| serve = require('koa-static'), | ||
| views = require('co-views'), | ||
| render = views(__dirname + '/views', { map: { html: 'jade' }, ext: 'jade' }), | ||
| monk = require('monk'), | ||
| wrap = require('co-monk'), | ||
| db = monk(config.db.name), | ||
| matches = require('./api/matches.js')(db); | ||
|
|
||
|
|
||
| var app = module.exports = koa(), | ||
| port = process.env.PORT || 8000, | ||
| env = process.env.NODE_ENV || 'development'; | ||
|
|
||
| app.use(logger()); | ||
|
|
||
| app.keys = [process.env.SESSION_SECRET || config.sessionSecret]; | ||
| // TODO: Mongo sessions | ||
| app.use(session()); | ||
|
|
||
| app.use(serve('static')); | ||
|
|
||
| // BEGIN: Auth | ||
| require('./auth.js') | ||
| app.use(passport.initialize()); | ||
| app.use(passport.session()); | ||
| // END: Auth | ||
|
|
||
| // BEGIN: Public routes | ||
| var publicRoutes = new Router(); | ||
|
|
||
| publicRoutes.get('/views/:area/:view', serveView); | ||
| publicRoutes.get('/views/:view', serveView); | ||
|
|
||
| function* serveView() { | ||
| var area = this.params.area, | ||
| view = this.params.view; | ||
|
|
||
| this.body = yield render(area ? area + '/' + view : view); | ||
| } | ||
|
|
||
| publicRoutes.get('/', function*() { | ||
| this.body = yield render('index'); | ||
| }); | ||
|
|
||
| publicRoutes.post('/login', koaBody, function*(next) { | ||
| var ctx = this; | ||
| yield* passport.authenticate('local', function*(err, user, info) { | ||
| if (err) throw err; | ||
| if (user === false) { | ||
| ctx.status = 401; | ||
| ctx.body = { success: false }; | ||
| } else { | ||
| yield ctx.login(user); | ||
| ctx.body = { success: true }; | ||
| } | ||
| }).call(this, next); | ||
| }); | ||
|
|
||
| // POST /login | ||
| /*publicRoutes.post('/login', koaBody, | ||
| passport.authenticate('local', , function (err, user) { | ||
| req.logIn(account, function() { | ||
| res.status(err ? 500 : 200).send(err ? err : account); | ||
| }); | ||
| }) | ||
| );*/ | ||
|
|
||
| publicRoutes.get('/logout', function*(next) { | ||
| this.logout(); | ||
| this.redirect('/'); | ||
| }); | ||
|
|
||
| publicRoutes.get('/auth/facebook', | ||
| passport.authenticate('facebook') | ||
| ); | ||
|
|
||
| publicRoutes.get('/auth/facebook/callback', | ||
| passport.authenticate('facebook', { | ||
| successRedirect: '/app', | ||
| failureRedirect: '/' | ||
| }) | ||
| ); | ||
|
|
||
| publicRoutes.get('/auth/twitter', | ||
| passport.authenticate('twitter') | ||
| ); | ||
|
|
||
| publicRoutes.get('/auth/twitter/callback', | ||
| passport.authenticate('twitter', { | ||
| successRedirect: '/app', | ||
| failureRedirect: '/' | ||
| }) | ||
| ); | ||
|
|
||
| publicRoutes.get('/auth/google', | ||
| passport.authenticate('google') | ||
| ); | ||
|
|
||
| publicRoutes.get('/auth/google/callback', | ||
| passport.authenticate('google', { | ||
| successRedirect: '/app', | ||
| failureRedirect: '/' | ||
| }) | ||
| ); | ||
|
|
||
| app.use(publicRoutes.middleware()); | ||
| // END: Public routes | ||
|
|
||
| // BEGIN: Authenticated routes | ||
| // Require authentication for all subsequently registered middleware | ||
| app.use(function*(next) { | ||
| if (this.isAuthenticated()) { | ||
| yield next; | ||
| } else { | ||
| //yield next; | ||
| this.redirect('/'); | ||
| } | ||
| }); | ||
|
|
||
| var secured = new Router(); | ||
|
|
||
| secured.post('/match', koaBody, matches.post); | ||
| secured.get('/match/:id', matches.show); | ||
|
|
||
| app.use(secured.middleware()); | ||
| // END: Authenticated routes | ||
|
|
||
| /* | ||
| app | ||
| .use(router.routes()) | ||
| .use(router.allowedMethods()); | ||
| */ | ||
|
|
||
| app.listen(port); | ||
| console.log('app listening on port: ', port); |