From 3b002a6fb136b9e7e534ffbcfedabed72fcd373d Mon Sep 17 00:00:00 2001 From: nanalelfe Date: Tue, 26 Jul 2016 21:45:42 -0400 Subject: Added passport-facbeook --- node_modules/passport-facebook/lib/strategy.js | 240 +++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 node_modules/passport-facebook/lib/strategy.js (limited to 'node_modules/passport-facebook/lib/strategy.js') diff --git a/node_modules/passport-facebook/lib/strategy.js b/node_modules/passport-facebook/lib/strategy.js new file mode 100644 index 0000000..f7881b1 --- /dev/null +++ b/node_modules/passport-facebook/lib/strategy.js @@ -0,0 +1,240 @@ +// Load modules. +var OAuth2Strategy = require('passport-oauth2') + , util = require('util') + , uri = require('url') + , crypto = require('crypto') + , Profile = require('./profile') + , InternalOAuthError = require('passport-oauth2').InternalOAuthError + , FacebookAuthorizationError = require('./errors/facebookauthorizationerror') + , FacebookTokenError = require('./errors/facebooktokenerror') + , FacebookGraphAPIError = require('./errors/facebookgraphapierror'); + + +/** + * `Strategy` constructor. + * + * The Facebook authentication strategy authenticates requests by delegating to + * Facebook using the OAuth 2.0 protocol. + * + * Applications must supply a `verify` callback which accepts an `accessToken`, + * `refreshToken` and service-specific `profile`, and then calls the `cb` + * callback supplying a `user`, which should be set to `false` if the + * credentials are not valid. If an exception occured, `err` should be set. + * + * Options: + * - `clientID` your Facebook application's App ID + * - `clientSecret` your Facebook application's App Secret + * - `callbackURL` URL to which Facebook will redirect the user after granting authorization + * + * Examples: + * + * passport.use(new FacebookStrategy({ + * clientID: '123-456-789', + * clientSecret: 'shhh-its-a-secret' + * callbackURL: 'https://www.example.net/auth/facebook/callback' + * }, + * function(accessToken, refreshToken, profile, cb) { + * User.findOrCreate(..., function (err, user) { + * cb(err, user); + * }); + * } + * )); + * + * @constructor + * @param {object} options + * @param {function} verify + * @access public + */ +function Strategy(options, verify) { + options = options || {}; + options.authorizationURL = options.authorizationURL || 'https://www.facebook.com/dialog/oauth'; + options.tokenURL = options.tokenURL || 'https://graph.facebook.com/oauth/access_token'; + options.scopeSeparator = options.scopeSeparator || ','; + + OAuth2Strategy.call(this, options, verify); + this.name = 'facebook'; + this._profileURL = options.profileURL || 'https://graph.facebook.com/v2.5/me'; + this._profileFields = options.profileFields || null; + this._enableProof = options.enableProof; + this._clientSecret = options.clientSecret; +} + +// Inherit from `OAuth2Strategy`. +util.inherits(Strategy, OAuth2Strategy); + + +/** + * Authenticate request by delegating to Facebook using OAuth 2.0. + * + * @param {http.IncomingMessage} req + * @param {object} options + * @access protected + */ +Strategy.prototype.authenticate = function(req, options) { + // Facebook doesn't conform to the OAuth 2.0 specification, with respect to + // redirecting with error codes. + // + // FIX: https://github.com/jaredhanson/passport-oauth/issues/16 + if (req.query && req.query.error_code && !req.query.error) { + return this.error(new FacebookAuthorizationError(req.query.error_message, parseInt(req.query.error_code, 10))); + } + + OAuth2Strategy.prototype.authenticate.call(this, req, options); +}; + +/** + * Return extra Facebook-specific parameters to be included in the authorization + * request. + * + * Options: + * - `display` Display mode to render dialog, { `page`, `popup`, `touch` }. + * + * @param {object} options + * @return {object} + * @access protected + */ +Strategy.prototype.authorizationParams = function (options) { + var params = {}; + + // https://developers.facebook.com/docs/reference/dialogs/oauth/ + if (options.display) { + params.display = options.display; + } + + // https://developers.facebook.com/docs/facebook-login/reauthentication/ + if (options.authType) { + params.auth_type = options.authType; + } + if (options.authNonce) { + params.auth_nonce = options.authNonce; + } + + return params; +}; + +/** + * Retrieve user profile from Facebook. + * + * This function constructs a normalized profile, with the following properties: + * + * - `provider` always set to `facebook` + * - `id` the user's Facebook ID + * - `username` the user's Facebook username + * - `displayName` the user's full name + * - `name.familyName` the user's last name + * - `name.givenName` the user's first name + * - `name.middleName` the user's middle name + * - `gender` the user's gender: `male` or `female` + * - `profileUrl` the URL of the profile for the user on Facebook + * - `emails` the proxied or contact email address granted by the user + * + * @param {string} accessToken + * @param {function} done + * @access protected + */ +Strategy.prototype.userProfile = function(accessToken, done) { + var url = uri.parse(this._profileURL); + if (this._enableProof) { + // Secure API call by adding proof of the app secret. This is required when + // the "Require AppSecret Proof for Server API calls" setting has been + // enabled. The proof is a SHA256 hash of the access token, using the app + // secret as the key. + // + // For further details, refer to: + // https://developers.facebook.com/docs/reference/api/securing-graph-api/ + var proof = crypto.createHmac('sha256', this._clientSecret).update(accessToken).digest('hex'); + url.search = (url.search ? url.search + '&' : '') + 'appsecret_proof=' + proof; + } + if (this._profileFields) { + var fields = this._convertProfileFields(this._profileFields); + if (fields !== '') { url.search = (url.search ? url.search + '&' : '') + 'fields=' + fields; } + } + url = uri.format(url); + + this._oauth2.get(url, accessToken, function (err, body, res) { + var json; + + if (err) { + if (err.data) { + try { + json = JSON.parse(err.data); + } catch (_) {} + } + + if (json && json.error && typeof json.error == 'object') { + return done(new FacebookGraphAPIError(json.error.message, json.error.type, json.error.code, json.error.error_subcode, json.error.fbtrace_id)); + } + return done(new InternalOAuthError('Failed to fetch user profile', err)); + } + + try { + json = JSON.parse(body); + } catch (ex) { + return done(new Error('Failed to parse user profile')); + } + + var profile = Profile.parse(json); + profile.provider = 'facebook'; + profile._raw = body; + profile._json = json; + + done(null, profile); + }); +}; + +/** + * Parse error response from Facebook OAuth 2.0 token endpoint. + * + * @param {string} body + * @param {number} status + * @return {Error} + * @access protected + */ +Strategy.prototype.parseErrorResponse = function(body, status) { + var json = JSON.parse(body); + if (json.error && typeof json.error == 'object') { + return new FacebookTokenError(json.error.message, json.error.type, json.error.code, json.error.error_subcode, json.error.fbtrace_id); + } + return OAuth2Strategy.prototype.parseErrorResponse.call(this, body, status); +}; + +/** + * Convert Facebook profile to a normalized profile. + * + * @param {object} profileFields + * @return {string} + * @access protected + */ +Strategy.prototype._convertProfileFields = function(profileFields) { + var map = { + 'id': 'id', + 'username': 'username', + 'displayName': 'name', + 'name': ['last_name', 'first_name', 'middle_name'], + 'gender': 'gender', + 'birthday': 'birthday', + 'profileUrl': 'link', + 'emails': 'email', + 'photos': 'picture' + }; + + var fields = []; + + profileFields.forEach(function(f) { + // return raw Facebook profile field to support the many fields that don't + // map cleanly to Portable Contacts + if (typeof map[f] === 'undefined') { return fields.push(f); }; + + if (Array.isArray(map[f])) { + Array.prototype.push.apply(fields, map[f]); + } else { + fields.push(map[f]); + } + }); + + return fields.join(','); +}; + + +// Expose constructor. +module.exports = Strategy; -- cgit v1.2.3