From ee2c4663d5500b1d91e76bef4a758744227706dd Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Fri, 7 Sep 2012 17:21:09 -0400 Subject: [PATCH] Pull in a bunch of changes from private branch, initial everyauth code --- lib/app/index.js | 24 ---- lib/app/schema.js | 3 +- lib/server/auth.js | 125 ++++++++++++++++++ lib/server/conf.js | 121 +++++++++++++++++ lib/server/index.js | 51 +++---- lib/server/{api.js => serverRoutes.js} | 18 ++- lib/server/setupStore.js | 30 ----- package.json | 12 +- src/app/index.coffee | 15 --- src/app/schema.coffee | 2 +- src/server/auth.coffee | 116 ++++++++++++++++ src/server/conf.coffee | 117 ++++++++++++++++ src/server/index.coffee | 51 ++----- .../{api.coffee => serverRoutes.coffee} | 15 +++ src/server/setupStore.coffee | 24 ---- views/app/index.html | 2 +- 16 files changed, 553 insertions(+), 173 deletions(-) create mode 100644 lib/server/auth.js create mode 100644 lib/server/conf.js rename lib/server/{api.js => serverRoutes.js} (62%) delete mode 100644 lib/server/setupStore.js create mode 100644 src/server/auth.coffee create mode 100644 src/server/conf.coffee rename src/server/{api.coffee => serverRoutes.coffee} (63%) delete mode 100644 src/server/setupStore.coffee diff --git a/lib/app/index.js b/lib/app/index.js index 7304380bb6..4748c6c5d6 100644 --- a/lib/app/index.js +++ b/lib/app/index.js @@ -27,30 +27,6 @@ get('/:uidParam?', function(page, model, _arg, next) { } userId = model.get('_userId'); return model.subscribe("users." + userId, function(err, user) { - var guid, newUser, task, _i, _len, _ref1; - if (!user.get('id')) { - newUser = require('node.extend')(true, {}, schema.userSchema); - _ref1 = content.defaultTasks; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - task = _ref1[_i]; - guid = task.id = require('derby/node_modules/racer').uuid(); - newUser.tasks[guid] = task; - switch (task.type) { - case 'habit': - newUser.habitIds.push(guid); - break; - case 'daily': - newUser.dailyIds.push(guid); - break; - case 'todo': - newUser.todoIds.push(guid); - break; - case 'reward': - newUser.rewardIds.push(guid); - } - } - model.set("users." + userId, newUser); - } model.ref('_user', user); model.set('_items', { armor: content.items.armor[parseInt(user.get('items.armor')) + 1], diff --git a/lib/app/schema.js b/lib/app/schema.js index e44750a7a1..92dcaff27b 100644 --- a/lib/app/schema.js +++ b/lib/app/schema.js @@ -11,7 +11,8 @@ module.exports.userSchema = userSchema = { items: { itemsEnabled: false, armor: 0, - weapon: 0 + weapon: 0, + rerollsRemaining: 5 }, tasks: {}, habitIds: [], diff --git a/lib/server/auth.js b/lib/server/auth.js new file mode 100644 index 0000000000..88c6c8e944 --- /dev/null +++ b/lib/server/auth.js @@ -0,0 +1,125 @@ +// Generated by CoffeeScript 1.3.3 +var conf, derby, model, sess; + +conf = require("./conf"); + +derby = require('derby'); + +model = void 0; + +sess = void 0; + +module.exports.setupPurlAuth = function(req) { + var acceptableUid, uidParam; + model = req.getModel(); + sess = req.session; + sess.userId || (sess.userId = derby.uuid()); + sess.auth || (sess.auth = { + userId: sess.userId + }); + uidParam = req.url.split('/')[1]; + acceptableUid = require('guid').isGuid(uidParam) || (uidParam === '3' || uidParam === '9'); + if (acceptableUid && sess.userId !== uidParam) { + sess.userId = uidParam; + } + return model.set('_userId', sess.userId); +}; + +module.exports.setupEveryauth = function(everyauth) { + everyauth.debug = true; + everyauth.everymodule.findUserById(function(id, callback) { + return model.fetch("users." + id, function(err, user) { + var content, guid, newUser, schema, task, _i, _len, _ref; + if (user && user.get('id')) { + return callback(null, user.get()); + } else { + schema = require('../app/schema'); + content = require('../app/content'); + newUser = require('node.extend')(true, {}, schema.userSchema); + _ref = content.defaultTasks; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + task = _ref[_i]; + guid = task.id = require('derby/node_modules/racer').uuid(); + newUser.tasks[guid] = task; + switch (task.type) { + case 'habit': + newUser.habitIds.push(guid); + break; + case 'daily': + newUser.dailyIds.push(guid); + break; + case 'todo': + newUser.todoIds.push(guid); + break; + case 'reward': + newUser.rewardIds.push(guid); + } + } + model.set("users." + id, newUser); + return callback(null, newUser); + } + }); + }); + return everyauth.facebook.appId(process.env.FACEBOOK_KEY).appSecret(process.env.FACEBOOK_SECRET).findOrCreateUser(function(session, accessToken, accessTokenExtra, fbUserMetadata) { + var q; + q = model.query('users').withEveryauth('facebook', fbUserMetadata.id); + model.fetch(q, function(err, user) { + console.log({ + err: err, + user: user + }); + if (user.get('id')) { + return sess.userId = user.get('id'); + } else { + model.setNull("users." + sess.userId + ".auth", { + 'facebook': {} + }); + return model.set("users." + sess.userId + ".auth.facebook", fbUserMetadata); + } + }); + return fbUserMetadata; + }).redirectPath("/"); +}; + +module.exports.setupQueries = function(store) { + store.query.expose('users', 'withId', function(id) { + return this.byId(id); + }); + store.query.expose('users', 'withEveryauth', function(provider, id) { + console.log({ + withEveryauth: { + provider: provider, + id: id + } + }); + return this.where("auth." + provider + ".id").equals(id); + }); + return store.queryAccess('users', 'withEveryauth', function(methodArgs) { + var accept; + accept = arguments[arguments.length - 1]; + return accept(true); + }); +}; + +module.exports.setupAccessControl = function(store) { + store.accessControl = true; + store.readPathAccess('users.*', function() { + var captures, next; + if (!(this.session && this.session.userId)) { + return; + } + captures = arguments[0]; + next = arguments[arguments.length - 1]; + return next(captures === this.session.userId); + }); + return store.writeAccess('*', 'users.*', function() { + var captures, next, pathArray; + if (!(this.session && this.session.userId)) { + return; + } + captures = arguments[0]; + next = arguments[arguments.length - 1]; + pathArray = captures.split('.'); + return next(pathArray[0] === this.session.userId); + }); +}; diff --git a/lib/server/conf.js b/lib/server/conf.js new file mode 100644 index 0000000000..6cd52300b8 --- /dev/null +++ b/lib/server/conf.js @@ -0,0 +1,121 @@ +// Generated by CoffeeScript 1.3.3 + +module.exports = { + fb: { + appId: "439694562721556", + appSecret: "d34327a67e32fe7936ababb72fa9639e" + }, + twit: { + consumerKey: "JLCGyLzuOK1BjnKPKGyQ", + consumerSecret: "GNqKfPqtzOcsCtFbGTMqinoATHvBcy1nzCTimeA9M0" + }, + github: { + appId: "11932f2b6d05d2a5fa18", + appSecret: "2603d1bc663b74d6732500c1e9ad05b0f4013593" + }, + instagram: { + clientId: "be147b077ddf49368d6fb5cf3112b9e0", + clientSecret: "b65ad83daed242c0aa059ffae42feddd" + }, + foursquare: { + clientId: "VUGE4VHJMKWALKDKIOH1HLD1OQNHTC0PBZZBUQSHJ3WKW04K", + clientSecret: "0LVAGARGUN05DEDDRVWNIMH4RFIHEFV0CERU3OITAZW1CXGX" + }, + gowalla: { + apiKey: "11cf666912004d709fa4bbf21718a82e", + apiSecret: "e1e23f135776452898a6d268129bf153" + }, + linkedin: { + apiKey: "pv6AWspODUeHIPNZfA531OYcFyB1v23u3y-KIADJdpyw54BXh-ciiQnduWf6FNRH", + apiSecret: "Pdx7DCoJRdAk0ai3joXsslZvK1DPCQwsLn-T17Opkae22ZYDP5R7gmAoFes9TNHy" + }, + google: { + clientId: "3335216477.apps.googleusercontent.com", + clientSecret: "PJMW_uP39nogdu0WpBuqMhtB" + }, + googlehybrid: { + consumerKey: "YOUR CONSUMER KEY HERE", + consumerSecret: "YOUR CONSUMER SECRET HERE" + }, + _37signals: { + clientId: "cd4bf9cd9ed828b6bed8b67e6b314cf8b90c8de5", + clientSecret: "07883c36b4f4493b70f31872ed8fbdb099ff1cef" + }, + angellist: { + clientId: "e5feda9308f55f16b0ef0e848f5b1e41", + clientSecret: "e0ec367efb9d59fa10bdd53ba268b81f" + }, + yahoo: { + consumerKey: "dj0yJmk9RVExRlhPRE9rV1hSJmQ9WVdrOWEyRTBVMUJoTm1zbWNHbzlNVE13TURFeU9UTTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD1iYg--", + consumerSecret: "efe6ae4982217630fe3aebf6e6fa1e82c02eba0b" + }, + readability: { + consumerKey: "Alfrednerstu", + consumerSecret: "MXGftcxrRNMYn66CVmADR3KRnygCdYSk" + }, + justintv: { + consumerKey: "enter your consumer key here", + consumerSecret: "enter your consumer secret here" + }, + tumblr: { + consumerKey: "TAofjqRz9iKiAjtPMnXzHELIeQAw8cqKCZVXaEFSAxBrrvV99f", + consumerSecret: "s8ldFtirtsnWGSiBjwpUwMct8Yh4sliS9Uiocqsv3bw0ovMtlR" + }, + dropbox: { + consumerKey: "uhfqnbely5stdtm", + consumerSecret: "jr7ofuwo32l7vkd" + }, + vimeo: { + consumerKey: "Enter your consumer key here", + consumerSecret: "Enter your consumer secret here" + }, + box: { + apiKey: "5hl66lbfy0quj8qhhzcn57dflb55y4rg" + }, + dwolla: { + clientId: "Enter your consumer key here", + clientSecret: "Enter your consumer secret here" + }, + vkontakte: { + appId: "Enter your app id here", + appSecret: "Enter your app secret here" + }, + mailru: { + appId: "Enter your app id here", + appSecret: "Enter your app secret here" + }, + skyrock: { + consumerKey: "a0ae943e20c5af88", + consumerSecret: "cjucy86r0fg4uxx3" + }, + evernote: { + oauthHost: "https://www.evernote.com", + consumerKey: "Enter your consumer key here", + consumerSecret: "Enter your consumer secret here" + }, + tripit: { + consumerKey: "a59bb58479f80e24dc6da1b1e61a107db743bc4c", + consumerSecret: "41dc4c0c39ac3ab162269a79f399eb180f753c66" + }, + _500px: { + consumerKey: "Enter your consumer key here", + consumerSecret: "Enter your consumer secret here" + }, + soundcloud: { + appId: "79dcfcb876e71dc18c1767b9ebe96298", + appSecret: "6f828028dab96838d07b2407cd5f80cd" + }, + mixi: { + consumerKey: "Enter your consumer key here", + consumerSecret: "Enter your consumer secret here", + scope: "r_profile" + }, + mailchimp: { + appId: "Enter your client/app id here", + appSecret: "Enter your client/app secret here" + }, + mendeley: { + consumerKey: "Enter your consumer key here", + consumerSecret: "Enter your consumer secret here" + } +}; diff --git a/lib/server/index.js b/lib/server/index.js index be3b7f2f27..65e85669e7 100644 --- a/lib/server/index.js +++ b/lib/server/index.js @@ -1,5 +1,5 @@ // Generated by CoffeeScript 1.3.3 -var MongoStore, ONE_YEAR, app, derby, express, expressApp, gzippo, habitrpgMiddleware, http, path, publicPath, racer, root, server, serverError, store; +var MongoStore, ONE_YEAR, app, auth, derby, everyauth, express, expressApp, gzippo, habitrpgMiddleware, http, path, publicPath, racer, root, server, serverError, store; http = require('http'); @@ -13,10 +13,14 @@ derby = require('derby'); app = require('../app'); +everyauth = require('everyauth'); + serverError = require('./serverError'); MongoStore = require('connect-mongo')(express); +auth = require('./auth'); + racer = require('derby/node_modules/racer'); racer.io.set('transports', ['xhr-polling']); @@ -42,6 +46,10 @@ store = derby.createStore({ listen: server }); +auth.setupQueries(store); + +auth.setupEveryauth(everyauth); + ONE_YEAR = 1000 * 60 * 60 * 24 * 365; root = path.dirname(path.dirname(__dirname)); @@ -49,24 +57,19 @@ root = path.dirname(path.dirname(__dirname)); publicPath = path.join(root, 'public'); habitrpgMiddleware = function(req, res, next) { - var acceptableUid, model, uidParam, _base; + var model; model = req.getModel(); - (_base = req.session).userId || (_base.userId = derby.uuid()); - uidParam = req.url.split('/')[1]; - acceptableUid = require('guid').isGuid(uidParam) || (uidParam === '3' || uidParam === '9'); - if (acceptableUid && req.session.userId !== uidParam) { - req.session.userId = uidParam; - } - model.set('_userId', req.session.userId); - model.set('_mobileDevice', /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent'))); + auth.setupPurlAuth(req); + auth.setupAccessControl(store); + model.set('_stripePubKey', process.env.STRIPE_PUB_KEY); model.set('_nodeEnv', process.env.NODE_ENV); - require('./setupStore').accessControl(store); + model.set('_mobileDevice', /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent'))); return next(); }; expressApp.use(express.favicon()).use(gzippo.staticGzip(publicPath, { maxAge: ONE_YEAR -})).use(express.compress()).use(express.bodyParser()).use(express.cookieParser()).use(store.sessionMiddleware({ +})).use(express.compress()).use(express.bodyParser()).use(express.methodOverride()).use(express.cookieParser()).use(store.sessionMiddleware({ secret: process.env.SESSION_SECRET || 'YOUR SECRET HERE', cookie: { maxAge: ONE_YEAR @@ -74,26 +77,6 @@ expressApp.use(express.favicon()).use(gzippo.staticGzip(publicPath, { store: new MongoStore({ url: process.env.NODE_DB_URI }) -})).use(store.modelMiddleware()).use(habitrpgMiddleware).use(app.router()).use(expressApp.router).use(serverError(root)); +})).use(store.modelMiddleware()).use(habitrpgMiddleware).use(everyauth.middleware()).use(app.router()).use(expressApp.router).use(serverError(root)); -require('./api')(expressApp); - -expressApp.post('/', function(req) { - return require('../app/reroll').stripeResponse(req); -}); - -expressApp.get('/privacy', function(req, res) { - var staticPages; - staticPages = derby.createStatic(root); - return staticPages.render('privacy', res); -}); - -expressApp.get('/terms', function(req, res) { - var staticPages; - staticPages = derby.createStatic(root); - return staticPages.render('terms', res); -}); - -expressApp.all('*', function(req) { - throw "404: " + req.url; -}); +require('./serverRoutes')(expressApp); diff --git a/lib/server/api.js b/lib/server/serverRoutes.js similarity index 62% rename from lib/server/api.js rename to lib/server/serverRoutes.js index 2e20163c6f..b570ce2f67 100644 --- a/lib/server/api.js +++ b/lib/server/serverRoutes.js @@ -22,7 +22,7 @@ module.exports = function(expressApp) { }); return res.send(200); }); - return expressApp.get('/:uid/down/:score?', function(req, res) { + expressApp.get('/:uid/down/:score?', function(req, res) { var model, score; score = parseInt(req.params.score) || 1; console.log({ @@ -40,4 +40,20 @@ module.exports = function(expressApp) { }); return res.send(200); }); + expressApp.get('/privacy', function(req, res) { + var staticPages; + staticPages = derby.createStatic(root); + return staticPages.render('privacy', res); + }); + expressApp.get('/terms', function(req, res) { + var staticPages; + staticPages = derby.createStatic(root); + return staticPages.render('terms', res); + }); + expressApp.all('*', function(req) { + throw "404: " + req.url; + }); + return expressApp.post('/', function(req) { + return require('../app/reroll').stripeResponse(req); + }); }; diff --git a/lib/server/setupStore.js b/lib/server/setupStore.js deleted file mode 100644 index 73bf9629f9..0000000000 --- a/lib/server/setupStore.js +++ /dev/null @@ -1,30 +0,0 @@ -// Generated by CoffeeScript 1.3.3 - -module.exports.queries = function(store) { - return store.query.expose('users', 'withId', function(id) { - return this.byId(id); - }); -}; - -module.exports.accessControl = function(store) { - store.accessControl = true; - store.readPathAccess('users.*', function() { - var captures, next; - if (!(this.session && this.session.userId)) { - return; - } - captures = arguments[0]; - next = arguments[arguments.length - 1]; - return next(captures === this.session.userId); - }); - return store.writeAccess('*', 'users.*', function() { - var captures, next, pathArray; - if (!(this.session && this.session.userId)) { - return; - } - captures = arguments[0]; - next = arguments[arguments.length - 1]; - pathArray = captures.split('.'); - return next(pathArray[0] === this.session.userId); - }); -}; diff --git a/package.json b/package.json index 7c74f8f7dc..0e00b4b001 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,20 @@ { "name": "habitrpg", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "0.0.0-101", + "version": "0.0.0-106", "main": "./server.js", "dependencies": { "derby": "0.3.13", "racer-db-mongo": "0.3.13", - "express": "3.0.0beta4", - "gzippo": ">=0.1.7", + "express": "*", + "gzippo": "git://github.com/dbashford/gzippo.git", "connect-mongo": ">=0.1.9", + "everyauth": "git://github.com/bnoguchi/everyauth#express3", "derby-ui-boot": "*", "guid": "*", "node.extend": "*", - "moment": "*" + "moment": "*", + "stripe": "*" }, "private": true, "devDependencies": { @@ -28,6 +30,6 @@ }, "engines": { "node": "0.8.x", - "npm": "1.1.x" + "npm": "1.1.x" } } diff --git a/src/app/index.coffee b/src/app/index.coffee index d625357cce..08a010325a 100644 --- a/src/app/index.coffee +++ b/src/app/index.coffee @@ -22,21 +22,6 @@ get '/:uidParam?', (page, model, {uidParam}, next) -> model.subscribe "users.#{userId}", (err, user) -> - # Create new user if none exists - unless user.get('id') - # deep clone, else further new users get duplicate objects - newUser = require('node.extend')(true, {}, schema.userSchema) - for task in content.defaultTasks - guid = task.id = require('derby/node_modules/racer').uuid() - newUser.tasks[guid] = task - switch task.type - when 'habit' then newUser.habitIds.push guid - when 'daily' then newUser.dailyIds.push guid - when 'todo' then newUser.todoIds.push guid - when 'reward' then newUser.rewardIds.push guid - model.set "users.#{userId}", newUser - # /end create new user - model.ref '_user', user # Store diff --git a/src/app/schema.coffee b/src/app/schema.coffee index f3ad11e1bb..2da64f4ea3 100644 --- a/src/app/schema.coffee +++ b/src/app/schema.coffee @@ -1,7 +1,7 @@ module.exports.userSchema = userSchema = { stats: { money: 0, exp: 0, lvl: 1, hp: 50 } - items: { itemsEnabled: false, armor: 0, weapon: 0 } + items: { itemsEnabled: false, armor: 0, weapon: 0, rerollsRemaining: 5 } tasks: {} habitIds: [] dailyIds: [] diff --git a/src/server/auth.coffee b/src/server/auth.coffee new file mode 100644 index 0000000000..478df7bdb7 --- /dev/null +++ b/src/server/auth.coffee @@ -0,0 +1,116 @@ +conf = require("./conf") +derby = require('derby') + +# FIXME I need access to model in everyauth, so that I can test whether a user exists in the database or +# create a new one otherwise. Everyauth configs must be declared before expressApp.use(...); howeve,r model is +# setup during expresApp.use(...). So my hack is - declare model here, define everyauth configs early in the server (like +# we should), then use our own middleware (habitrpgMiddleware) to model during expresApp.use(...) +model = undefined +sess = undefined + +# Ultimate goal: set `sess.auth.userId` + +## PURL authentication +# This is temporary and will go away when everyauth is setup. It tests to see if +# a UUID was used (bookmarked private url), and restores the user session if so +module.exports.setupPurlAuth = (req) -> + model = req.getModel() + sess = req.session + + # Setup userId for new users + sess.userId ||= derby.uuid() + sess.auth ||= {userId: sess.userId} # prepare for everyauth + # Previously saved session (eg, http://localhost/{guid}) (temporary solution until authentication built) + uidParam = req.url.split('/')[1] + acceptableUid = require('guid').isGuid(uidParam) or (uidParam in ['3','9']) + if acceptableUid && sess.userId!=uidParam + # TODO test whether user exists: ```model.fetch("users.#{uidParam}", function(err,user){if(user.get(..){})}})```, but doesn't seem to work + sess.userId = uidParam + model.set '_userId', sess.userId + +## Setup callbacks for serializing/deserializing users to/from model. +module.exports.setupEveryauth = (everyauth) -> + + everyauth.debug = true + + everyauth.everymodule.findUserById (id, callback) -> + model.fetch "users.#{id}", (err, user) -> + if user && user.get('id') + callback null, user.get() # FIXME what format are we supposed to return user? + else + # Create new user if none exists + # deep clone, else further new users get duplicate objects + schema = require('../app/schema') + content = require('../app/content') + newUser = require('node.extend')(true, {}, schema.userSchema) + for task in content.defaultTasks + guid = task.id = require('derby/node_modules/racer').uuid() + newUser.tasks[guid] = task + switch task.type + when 'habit' then newUser.habitIds.push guid + when 'daily' then newUser.dailyIds.push guid + when 'todo' then newUser.todoIds.push guid + when 'reward' then newUser.rewardIds.push guid + model.set "users.#{id}", newUser + callback null, newUser + + # Facebook Authentication Logic + everyauth + .facebook + .appId(process.env.FACEBOOK_KEY) + .appSecret(process.env.FACEBOOK_SECRET) + .findOrCreateUser( (session, accessToken, accessTokenExtra, fbUserMetadata) -> + # usersByFbId[fbUserMetadata.id] or (usersByFbId[fbUserMetadata.id] = addUser("facebook", fbUserMetadata)) + q = model.query('users').withEveryauth('facebook', fbUserMetadata.id) + model.fetch q, (err,user) -> + console.log {err:err,user:user} #FIXME this is always returning user:null, however; this runs fine on the client + if user.get('id') + sess.userId = user.get('id') # is necessary? + else + model.setNull "users.#{sess.userId}.auth", {'facebook':{}} + model.set "users.#{sess.userId}.auth.facebook", fbUserMetadata + fbUserMetadata + ).redirectPath "/" + + # addUser = (source, sourceUser) -> + # user = undefined + # if arguments.length is 1 # password-based + # user = sourceUser = source + # user.id = ++nextUserId + # return usersById[nextUserId] = user + # else # non-password-based + # user = usersById[++nextUserId] = id: nextUserId + # user[source] = sourceUser + # user + +module.exports.setupQueries = (store) -> + ## Setup Queries + store.query.expose 'users', 'withId', (id) -> + @byId(id) + store.query.expose 'users', 'withEveryauth', (provider, id) -> + console.log {withEveryauth:{provider:provider,id:id}} + @where("auth.#{provider}.id").equals(id) + store.queryAccess 'users', 'withEveryauth', (methodArgs) -> + accept = arguments[arguments.length-1] + accept(true) #for now + +module.exports.setupAccessControl = (store) -> + store.accessControl = true + + # Callback signatures here have variable length, eg `callback(captures..., next)` + # Is using arguments[n] the correct way to handle this? + + store.readPathAccess 'users.*', () -> #captures, next) -> + return unless @session && @session.userId # https://github.com/codeparty/racer/issues/37 + captures = arguments[0] + next = arguments[arguments.length-1] + # console.log { readPathAccess: {captures:captures, sessionUserId:@session.userId, next:next} } + next(captures == @session.userId) + + store.writeAccess '*', 'users.*', () -> #captures, value, next) -> + return unless @session && @session.userId + captures = arguments[0] + next = arguments[arguments.length-1] + pathArray = captures.split('.') + # console.log { writeAccess: {captures:captures, next:next, pathArray:pathArray, arguments:arguments} } + next(pathArray[0] == @session.userId) \ No newline at end of file diff --git a/src/server/conf.coffee b/src/server/conf.coffee new file mode 100644 index 0000000000..33bf4c6e93 --- /dev/null +++ b/src/server/conf.coffee @@ -0,0 +1,117 @@ +module.exports = + fb: + appId: "439694562721556" + appSecret: "d34327a67e32fe7936ababb72fa9639e" + + twit: + consumerKey: "JLCGyLzuOK1BjnKPKGyQ" + consumerSecret: "GNqKfPqtzOcsCtFbGTMqinoATHvBcy1nzCTimeA9M0" + + github: + appId: "11932f2b6d05d2a5fa18" + appSecret: "2603d1bc663b74d6732500c1e9ad05b0f4013593" + + instagram: + clientId: "be147b077ddf49368d6fb5cf3112b9e0" + clientSecret: "b65ad83daed242c0aa059ffae42feddd" + + foursquare: + clientId: "VUGE4VHJMKWALKDKIOH1HLD1OQNHTC0PBZZBUQSHJ3WKW04K" + clientSecret: "0LVAGARGUN05DEDDRVWNIMH4RFIHEFV0CERU3OITAZW1CXGX" + + gowalla: + apiKey: "11cf666912004d709fa4bbf21718a82e" + apiSecret: "e1e23f135776452898a6d268129bf153" + + linkedin: + apiKey: "pv6AWspODUeHIPNZfA531OYcFyB1v23u3y-KIADJdpyw54BXh-ciiQnduWf6FNRH" + apiSecret: "Pdx7DCoJRdAk0ai3joXsslZvK1DPCQwsLn-T17Opkae22ZYDP5R7gmAoFes9TNHy" + + google: + clientId: "3335216477.apps.googleusercontent.com" + clientSecret: "PJMW_uP39nogdu0WpBuqMhtB" + + googlehybrid: + consumerKey: "YOUR CONSUMER KEY HERE" + consumerSecret: "YOUR CONSUMER SECRET HERE" + + _37signals: + clientId: "cd4bf9cd9ed828b6bed8b67e6b314cf8b90c8de5" + clientSecret: "07883c36b4f4493b70f31872ed8fbdb099ff1cef" + + angellist: + clientId: "e5feda9308f55f16b0ef0e848f5b1e41" + clientSecret: "e0ec367efb9d59fa10bdd53ba268b81f" + + yahoo: + consumerKey: "dj0yJmk9RVExRlhPRE9rV1hSJmQ9WVdrOWEyRTBVMUJoTm1zbWNHbzlNVE13TURFeU9UTTJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD1iYg--" + consumerSecret: "efe6ae4982217630fe3aebf6e6fa1e82c02eba0b" + + readability: + consumerKey: "Alfrednerstu" + consumerSecret: "MXGftcxrRNMYn66CVmADR3KRnygCdYSk" + + justintv: + consumerKey: "enter your consumer key here" + consumerSecret: "enter your consumer secret here" + + tumblr: + consumerKey: "TAofjqRz9iKiAjtPMnXzHELIeQAw8cqKCZVXaEFSAxBrrvV99f" + consumerSecret: "s8ldFtirtsnWGSiBjwpUwMct8Yh4sliS9Uiocqsv3bw0ovMtlR" + + dropbox: + consumerKey: "uhfqnbely5stdtm" + consumerSecret: "jr7ofuwo32l7vkd" + + vimeo: + consumerKey: "Enter your consumer key here" + consumerSecret: "Enter your consumer secret here" + + box: + apiKey: "5hl66lbfy0quj8qhhzcn57dflb55y4rg" + + dwolla: + clientId: "Enter your consumer key here" + clientSecret: "Enter your consumer secret here" + + vkontakte: + appId: "Enter your app id here" + appSecret: "Enter your app secret here" + + mailru: + appId: "Enter your app id here" + appSecret: "Enter your app secret here" + + skyrock: + consumerKey: "a0ae943e20c5af88" + consumerSecret: "cjucy86r0fg4uxx3" + + evernote: + oauthHost: "https://www.evernote.com" + consumerKey: "Enter your consumer key here" + consumerSecret: "Enter your consumer secret here" + + tripit: + consumerKey: "a59bb58479f80e24dc6da1b1e61a107db743bc4c" + consumerSecret: "41dc4c0c39ac3ab162269a79f399eb180f753c66" + + _500px: + consumerKey: "Enter your consumer key here" + consumerSecret: "Enter your consumer secret here" + + soundcloud: + appId: "79dcfcb876e71dc18c1767b9ebe96298" + appSecret: "6f828028dab96838d07b2407cd5f80cd" + + mixi: + consumerKey: "Enter your consumer key here" + consumerSecret: "Enter your consumer secret here" + scope: "r_profile" + + mailchimp: + appId: "Enter your client/app id here" + appSecret: "Enter your client/app secret here" + + mendeley: + consumerKey: "Enter your consumer key here" + consumerSecret: "Enter your consumer secret here" \ No newline at end of file diff --git a/src/server/index.coffee b/src/server/index.coffee index 5ccc467aeb..db1044fae5 100644 --- a/src/server/index.coffee +++ b/src/server/index.coffee @@ -4,8 +4,10 @@ express = require 'express' gzippo = require 'gzippo' derby = require 'derby' app = require '../app' +everyauth = require('everyauth') serverError = require './serverError' MongoStore = require('connect-mongo')(express) +auth = require('./auth') ## RACER CONFIGURATION ## @@ -25,6 +27,8 @@ derby.use(require 'racer-db-mongo') store = derby.createStore db: {type: 'Mongo', uri: process.env.NODE_DB_URI} listen: server +auth.setupQueries(store) +auth.setupEveryauth(everyauth) ONE_YEAR = 1000 * 60 * 60 * 24 * 365 root = path.dirname path.dirname __dirname @@ -33,25 +37,14 @@ publicPath = path.join root, 'public' habitrpgMiddleware = (req, res, next) -> model = req.getModel() - ## PURL authentication - # Setup userId for new users - req.session.userId ||= derby.uuid() - # Previously saved session (eg, http://localhost/{guid}) (temporary solution until authentication built) - uidParam = req.url.split('/')[1] - acceptableUid = require('guid').isGuid(uidParam) or (uidParam in ['3','9']) - if acceptableUid && req.session.userId!=uidParam - # TODO test whether user exists: ```model.fetch("users.#{uidParam}", function(err,user){if(user.get(..){})}})```, but doesn't seem to work - req.session.userId = uidParam - model.set '_userId', req.session.userId - - ## Set _mobileDevice to true or false so view can exclude portions from mobile device - model.set '_mobileDevice', /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header 'User-Agent') - - ## Same for production/development + auth.setupPurlAuth(req) + auth.setupAccessControl(store) + + model.set '_stripePubKey', process.env.STRIPE_PUB_KEY model.set '_nodeEnv', process.env.NODE_ENV - ## Setup access control - require('./setupStore').accessControl(store) + ## Set _mobileDevice to true or false so view can exclude portions from mobile device + model.set '_mobileDevice', /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header 'User-Agent') next() @@ -64,7 +57,7 @@ expressApp # Uncomment to add form data parsing support .use(express.bodyParser()) - # .use(express.methodOverride()) + .use(express.methodOverride()) # Uncomment and supply secret to add Derby session handling # Derby session middleware creates req.session and socket.io sessions @@ -74,32 +67,16 @@ expressApp cookie: {maxAge: ONE_YEAR} store: new MongoStore(url: process.env.NODE_DB_URI) ) - + # Adds req.getModel method .use(store.modelMiddleware()) # Middelware can be inserted after the modelMiddleware and before # the app router to pass server accessible data to a model .use(habitrpgMiddleware) + .use(everyauth.middleware()) # Creates an express middleware from the app's routes .use(app.router()) .use(expressApp.router) .use(serverError root) -## SERVER ONLY ROUTES ## - -require('./api')(expressApp) - -expressApp.post '/', (req) -> - require('../app/reroll').stripeResponse(req) - -expressApp.get '/privacy', (req, res) -> - staticPages = derby.createStatic root - staticPages.render 'privacy', res - -expressApp.get '/terms', (req, res) -> - staticPages = derby.createStatic root - staticPages.render 'terms', res - -expressApp.all '*', (req) -> - throw "404: #{req.url}" - \ No newline at end of file +require('./serverRoutes')(expressApp) diff --git a/src/server/api.coffee b/src/server/serverRoutes.coffee similarity index 63% rename from src/server/api.coffee rename to src/server/serverRoutes.coffee index 1beed9728f..2b4be2447a 100644 --- a/src/server/api.coffee +++ b/src/server/serverRoutes.coffee @@ -1,6 +1,7 @@ scoring = require('../app/scoring') module.exports = (expressApp) -> + expressApp.get '/:uid/up/:score?', (req, res) -> score = parseInt(req.params.score) || 1 console.log {score:score} @@ -18,3 +19,17 @@ module.exports = (expressApp) -> return if err || !user.get() scoring.score({user:user, direction:'down'}) res.send(200) + + expressApp.get '/privacy', (req, res) -> + staticPages = derby.createStatic root + staticPages.render 'privacy', res + + expressApp.get '/terms', (req, res) -> + staticPages = derby.createStatic root + staticPages.render 'terms', res + + expressApp.all '*', (req) -> + throw "404: #{req.url}" + + expressApp.post '/', (req) -> + require('../app/reroll').stripeResponse(req) diff --git a/src/server/setupStore.coffee b/src/server/setupStore.coffee deleted file mode 100644 index c4a790227e..0000000000 --- a/src/server/setupStore.coffee +++ /dev/null @@ -1,24 +0,0 @@ -module.exports.queries = (store) -> - store.query.expose 'users', 'withId', (id) -> - @byId(id) - -module.exports.accessControl = (store) -> - store.accessControl = true - - # FIXME callback signatures here have variable length, eg `callback(captures..., next)` - # Is using arguments[n] the correct way to handle this? - - store.readPathAccess 'users.*', () -> #captures, next) -> - return unless @session && @session.userId # https://github.com/codeparty/racer/issues/37 - captures = arguments[0] - next = arguments[arguments.length-1] - # console.log { readPathAccess: {captures:captures, sessionUserId:@session.userId, next:next} } - next(captures == @session.userId) - - store.writeAccess '*', 'users.*', () -> #captures, value, next) -> - return unless @session && @session.userId - captures = arguments[0] - next = arguments[arguments.length-1] - pathArray = captures.split('.') - # console.log { writeAccess: {captures:captures, next:next, pathArray:pathArray, arguments:arguments} } - next(pathArray[0] == @session.userId) diff --git a/views/app/index.html b/views/app/index.html index 6fc8d3968a..97c33d6135 100644 --- a/views/app/index.html +++ b/views/app/index.html @@ -10,7 +10,7 @@