Ejemplo n.º 1
0
//set some vars
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('cookie-session');
var methodOverride = require('method-override');

var passport = require('passport');
var util = require('util');

// var appName = require('../../package.json').name;
var appName = require('./package.json').name
            || require('../../package.json').name;

var ports = require('ports');
var port = ports.getPort(appName + '-hoodie-plugin-social');
var compareVersion = require('compare-version');

// var hoodieServerVer = require('../hoodie-server/package.json').version;
var hoodieServerVer = require('hoodie-server/package.json').version
                    || require('../hoodie-server/package.json').version;

var facebookStrategy = require('passport-facebook').Strategy;
var twitterStrategy = require('passport-twitter').Strategy;
var googleStrategy = require('passport-google-oauth').OAuth2Strategy; //from git://github.com/z0mt3c/passport-google-oauth.git
var authServer = express();
var auths = {};
var host = null;
var socialApi = require('./social_api.js');
var moment = require('moment');
var socialTasks = []; //keeps track of social active tasks
Ejemplo n.º 2
0
module.exports = function (hoodie, cb) {
    //check for plugin config items and set if not there
    if (!hoodie.config.get('port')) hoodie.config.set('port', ports.getPort(appName+'-hoodie-plugin-social'));
    if (!hoodie.config.get('facebook_config')) hoodie.config.set('facebook_config', {"enabled":false,"settings":{"clientID":"","clientSecret":""}});
    if (!hoodie.config.get('twitter_config')) hoodie.config.set('twitter_config', {"enabled":false,"settings":{"consumerKey":"","consumerSecret":""}});
    if (!hoodie.config.get('google_config')) hoodie.config.set('google_config', {"enabled":false,"settings":{}});
    
    //get the CouchDB config then setup proxy
    hoodie.request('get', '_config', {}, function(err, data){
        var port = hoodie.config.get('port');
        if (!data.httpd_global_handlers._auth || (data.httpd_global_handlers._auth.indexOf(port) == -1)) {
            var value = '{couch_httpd_proxy, handle_proxy_req, <<"http://0.0.0.0:'+port+'">>}';
            hoodie.request('PUT', '_config/httpd_global_handlers/_auth/', {data:JSON.stringify(value)},function(err, data){
                if (err) console.log(err);
            });
        }
    });
        
    //setup base route for front end status calls
    authServer.get('/', function(req, res) {
        //set the host directly from front end query parameter
        //work around until https://github.com/hoodiehq/hoodie-server/issues/183 is resolved
        if (req.query.uri) host = req.query.uri;
        
        //check if we intend to destroy the current auth object
        if (req.query.destroy == 'true' && req.session.ref) {
            delete auths[req.session.ref];
            req.session.destroy();
            res.redirect(host+'/');
            return false;
        }
        
        //either send the current auth object or create one
        if ((req.session.ref != undefined) && (auths[req.session.ref] != undefined)) {
            res.send(auths[req.session.ref]);
        } else {
            setAuthObj(function(ref) {
                req.session.ref = ref;
                res.send(auths[req.session.ref]);
            });
        }
    });
        
    //setup generic authenticate route (redirect destination from specific provider routes)
    authServer.get('/authenticate', function(req, res) {
        if (passport._strategies[req.query.provider] == undefined) {
            invokeStrategy(req.query.provider, res);
        } else {
            if (req.query.provider == 'facebook') {
                passport.authenticate(req.query.provider, { display: 'touch' })(req, res);
            } else {
                passport.authenticate(req.query.provider)(req, res);
            }
        }
    });
    
    //setup facebook specific authenicate and callback routes
    authServer.get('/authenticate/facebook', function(req, res) { res.redirect(host+'/authenticate?provider=facebook'); });
    authServer.get('/facebook/callback', passport.authenticate('facebook'), function(req, res) {res.redirect(host+'/callback?provider=facebook');});

    //setup twitter specific authenicate and callback routes
    authServer.get('/authenticate/twitter', function(req, res) { res.redirect(host+'/authenticate?provider=twitter'); });
    authServer.get('/twitter/callback', passport.authenticate('twitter'), function(req, res) {res.redirect(host+'/callback?provider=twitter');});
    
    //setup google specific authenicate and callback routes
    authServer.get('/authenticate/google', function(req, res) { res.redirect(host+'/authenticate?provider=google'); });
    authServer.get('/google/callback', passport.authenticate('google'), function(req, res) {res.redirect(host+'/callback?provider=google');});

    //setup generic callback route (redirect destination from specific provider routes)
    authServer.get('/callback', function(req, res) {
        //generate a auth obj if we need one
        if (req.session.ref == undefined || (auths[req.session.ref] == undefined)) {
            setAuthObj(function(ref){
                req.session.ref = ref;
            });
        }
        
        //if there's no email provided by the provider (like twitter), we will create our own id
        var id = (req.user.emails == undefined) ? req.user.displayName.replace(' ','_').toLowerCase()+'_'+req.user.id : req.user.emails[0].value;
        
        //update the auth object values
        auths[req.session.ref]['authenticated'] = true;
        auths[req.session.ref]['provider'] = req.query.provider;
        auths[req.session.ref]['id'] = id;
        auths[req.session.ref]['full_profile'] = req.user;
        delete auths[req.session.ref]['auth_urls'];
               
        //check if we have a couch user and act accordingly
        hoodie.account.find('user', id, function(err, data){
            if (!err) {
                //set the auth time value (used for cleanup)
                auths[req.session.ref]['auth_time'] = new Date().getTime();
                
                //temporarily change the users password - this is where the magic happens!
                auths[req.session.ref]['temp_pass'] = Math.random().toString(36).slice(2,11);
                hoodie.account.update('user', id, {password:auths[req.session.ref]['temp_pass']}, function(err, data){ console.log(data); });
                
                //give the user some visual feedback
                res.send('<html><head><script src="http://fgnass.github.io/spin.js/dist/spin.min.js"></script></head><body onload="/*self.close();*/" style="margin:0; padding:0; width:100%; height: 100%; display: table;"><div style="display:table-cell; text-align:center; vertical-align: middle;"><div id="spin" style="display:inline-block;"></div></div><script>var spinner=new Spinner().spin(); document.getElementById("spin").appendChild(spinner.el);</script></body></html>');
            } else {
                //assume the error is because the couch user is not there and just create one
                var uuid = Math.random().toString(36).slice(2,9);
                var timeStamp = new Date();
                var userdoc = {
                    id: id,
                    password: Math.random().toString(36).slice(2,11),
                    ownerHash: uuid,
                    createdAt: timeStamp,
                    updatedAt: timeStamp,
                    signedUpAt: timeStamp,
                    database: 'user/'+uuid,
                    name: 'user/'+id
                };
                hoodie.account.add('user', userdoc, function(err, data){
                    //cycle back through so we can catch the fully created user
                    if (!err) res.redirect(host+'/'+req.query.provider+'/callback');
                });
            }
        });
    });
    
    //No need to keep this stuff around, so lets clean up after ourselves
    var cleanupInterval = setInterval(function() {cleanupAuths();},15000);
    function cleanupAuths() {
        var now = new Date().getTime();
        for(var i in auths) {
            if (now - auths[i].auth_time >= 30000) {
                delete auths[i];
            }
        }
    }
    
    //function to invoke a strategy
    function invokeStrategy(provider, res) {
        config = hoodie.config.get(provider+'_config');
        if (config.enabled) {
            settings = config.settings;
            settings['failureRedirect'] = '/fail'; //todo - set this route up
            if (provider == 'facebook') {
                settings['callbackURL'] = host+'/facebook/callback';
                var providerStrategy = facebookStrategy;
                var verify = function(accessToken,refreshToken,profile,done){process.nextTick(function(){return done(null,profile);});}
            } else if (provider == 'twitter') {
                settings['callbackURL'] = host+'/twitter/callback';
                var providerStrategy = twitterStrategy;
                var verify = function(accessToken,refreshToken,profile,done){process.nextTick(function(){return done(null,profile);});}
            } else if (provider == 'google') {
                settings['returnURL'] = host+'/google/callback';
                settings['realm'] = host;
                var providerStrategy = googleStrategy;
                var verify = function(identifier,profile,done){process.nextTick(function(){return done(null,profile);});}
            }
            passport.use(new providerStrategy(settings,verify));
            res.redirect(host+'/authenticate/'+provider);
        } else {
            res.send('Provider not configured');
            return false;
        }
    }
    
    //function to assign a an auth object
    function setAuthObj(callback) {
        //generate random reference ID
        var ref = Math.random().toString(36).slice(2);
        
        //set a new request object for tracking progress
        auths[ref] = {
            "requested": new Date().getTime(),
            "authenticated":false,
            "auth_urls": {
                "facebook":host+"/authenticate/facebook",
                "twitter":host+"/authenticate/twitter",
                "google":host+"/authenticate/google"
            }
        };
        callback(ref);
    }
    
    //start the server on load
    var port = hoodie.config.get('port');
    authServer.listen(port);
    console.log('Hoodie Social Plugin: Listening on port '+port);
    
    //Hoodie Callback
    cb();
}
Ejemplo n.º 3
0
exports.getConfig = function (platform, env, project_dir, argv) {
    // location of project's package.json
    var pkgfile = path.resolve(project_dir, 'package.json');

    // default platform-agnostic config
    var cfg = {
        project_dir: project_dir,
        host: process.env.HOODIE_BIND_ADDRESS || '127.0.0.1',
        app: JSON.parse(fs.readFileSync(pkgfile)),
        domain: 'dev',
        local_tld: false,
        platform: platform,
        open_browser: true
    };

    // set the Hoodie instance ID, this is used to check
    // against the user roles when doing a test for Hoodie admin
    cfg.id = cfg.app.name;
    cfg.www_port = ports.getPort(cfg.id + '-www');
    cfg.admin_port = ports.getPort(cfg.id + '-admin');

    // add CouchDB paths to config
    cfg = _.extend(cfg, exports.getCouch(env));
    // add Hoodie paths to config
    cfg.hoodie = {
        app_path: path.resolve(cfg.project_dir, 'data')
    };

    // do magic firewall stuff for .dev domains on mac
    if (platform === 'darwin') {
        // only if it is installed
        try {
            require('local-tld');
            cfg.local_tld = true;
        } catch(e) {
            // no local-tld, it’s fine, carry on.
        }
    }

    // option to turn on/off local-tld on command-line
    if (argv.hasOwnProperty('local-tld')) {
        cfg.local_tld = argv['local-tld'];
    }

    if (exports.isNodejitsu(env)) {
        // Nodejitsu config
        cfg.host = '0.0.0.0';
        cfg.domain = 'jit.su';
        cfg.couch.run = false;

        // move the www and admin ports and run a nodejitsu server
        // to proxy requests to them based on subdomains (since we don't
        // run local-tld on nodejitsu)
        cfg.www_port = 8180;
        cfg.admin_port = 8190;
        cfg.run_nodejitsu_server = true;
        cfg.open_browser = false;

        // turn off fancy terminal stuff where possible
        cfg.boring = true;

        if (!env.COUCH_URL) {
            throw new Error('COUCH_URL environment variable not set');
        }
        if (!env.HOODIE_ADMIN_USER) {
            throw new Error('HOODIE_ADMIN_USER environment variable not set');
        }
        if (!env.HOODIE_ADMIN_PASS) {
            throw new Error('HOODIE_ADMIN_PASS environment variable not set');
        }
    }


    if(!process.env.COUCH_URL) {
        cfg.couch.port = ports.getPort(cfg.id + '-couch');
    }

    // option to turn on/off open browser on command-line
    if (argv.hasOwnProperty('open-browser')) {
        cfg.open_browser = argv['open-browser'];
    }

    if (process.env.CI) {
        cfg.open_browser = false;
    }


    if (!cfg.couch.url) {
        cfg.couch.url = 'http://' + cfg.host + ':' + cfg.couch.port;
    }

    // get the host for couchb url
    var parsed = url.parse(cfg.couch.url);
    cfg.couch.host = parsed.hostname;
    cfg.couch.port = parsed.port || 80;

    return cfg;
};