From 8a06118d94f929cead4cbd1067c6cb266bd089d8 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 5 Apr 2017 11:39:54 -0600 Subject: [PATCH 1/4] Added coral facebook auth plugin, some circ dep fixes --- .eslintignore | 5 +-- .gitignore | 16 ++++++--- README.md | 6 ---- app.js | 12 +++++++ package.json | 1 - plugins.json | 5 +++ plugins/coral-plugin-facebook-auth/README.md | 26 ++++++++++++++ plugins/coral-plugin-facebook-auth/index.js | 7 ++++ .../coral-plugin-facebook-auth/package.json | 9 +++++ .../server/passport.js | 27 +++++++++++++++ .../server/router.js | 20 +++++++++++ plugins/coral-plugin-facebook-auth/yarn.lock | 34 +++++++++++++++++++ routes/api/auth/index.js | 18 +--------- services/passport.js | 33 ------------------ yarn.lock | 25 +------------- 15 files changed, 156 insertions(+), 88 deletions(-) create mode 100644 plugins.json create mode 100644 plugins/coral-plugin-facebook-auth/README.md create mode 100644 plugins/coral-plugin-facebook-auth/index.js create mode 100644 plugins/coral-plugin-facebook-auth/package.json create mode 100644 plugins/coral-plugin-facebook-auth/server/passport.js create mode 100644 plugins/coral-plugin-facebook-auth/server/router.js create mode 100644 plugins/coral-plugin-facebook-auth/yarn.lock diff --git a/.eslintignore b/.eslintignore index 6ec4c0c88..d506a20c2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,6 @@ dist client/lib **/*.html -plugins/ -plugins/**/node_modules \ No newline at end of file +plugins/* +!plugins/coral-plugin-facebook-auth +node_modules \ No newline at end of file diff --git a/.gitignore b/.gitignore index 62a765fff..4ad15747d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,18 @@ node_modules -npm-debug.log* + dist -test/e2e/reports + +npm-debug.log* dump.rdb + .env *.cfg + .idea/ -coverage/ *.swp -plugins -plugins.json + +test/e2e/reports +coverage/ + +plugins/* +!plugins/coral-plugin-facebook-auth \ No newline at end of file diff --git a/README.md b/README.md index 3111446ea..b88138425 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,6 @@ The Talk application looks for the following configuration values either as envi secure cookies. - `TALK_ROOT_URL` (*required*) - root url of the installed application externally available in the format: `://` without the path. - -- `TALK_FACEBOOK_APP_ID` (*required for login via fb*) - the Facebook app id for your Facebook -Login enabled app. -- `TALK_FACEBOOK_APP_SECRET` (*required for login via fb*) - the Facebook app secret for your -Facebook Login enabled app. - - `TALK_SMTP_EMAIL` (*required for email*) - the address to send emails from using the SMTP provider. - `TALK_SMTP_USERNAME` (*required for email*) - username of the SMTP provider you are using. diff --git a/app.js b/app.js index 3ae03ec72..e1e864b10 100644 --- a/app.js +++ b/app.js @@ -4,6 +4,7 @@ const morgan = require('morgan'); const path = require('path'); const helmet = require('helmet'); const {passport} = require('./services/passport'); +const plugins = require('./services/plugins'); const session = require('express-session'); const enabled = require('debug').enabled; const RedisStore = require('connect-redis')(session); @@ -75,6 +76,17 @@ app.use(session(session_opts)); // PASSPORT MIDDLEWARE //============================================================================== +const passportDebug = require('debug')('talk:passport'); + +// Install the passport plugins. +plugins.get('server', 'passport').forEach((plugin) => { + passportDebug(`added plugin '${plugin.plugin.name}'`); + + // Pass the passport.js instance to the plugin to allow it to inject it's + // functionality. + plugin.passport(passport); +}); + // Setup the PassportJS Middleware. app.use(passport.initialize()); app.use(passport.session()); diff --git a/package.json b/package.json index 5dcb93bcc..0201ab75c 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,6 @@ "nodemailer": "^2.6.4", "parse-duration": "^0.1.1", "passport": "^0.3.2", - "passport-facebook": "^2.1.1", "passport-local": "^1.0.0", "react-apollo": "^0.10.0", "react-recaptcha": "^2.2.6", diff --git a/plugins.json b/plugins.json new file mode 100644 index 000000000..40702cde9 --- /dev/null +++ b/plugins.json @@ -0,0 +1,5 @@ +{ + "server": [ + "coral-plugin-facebook-auth" + ] +} diff --git a/plugins/coral-plugin-facebook-auth/README.md b/plugins/coral-plugin-facebook-auth/README.md new file mode 100644 index 000000000..4982ae368 --- /dev/null +++ b/plugins/coral-plugin-facebook-auth/README.md @@ -0,0 +1,26 @@ +# coral-plugin-facebook-auth + +This plugin provides facebook authentication support for Talk. + +## Configuration + +This plugin looks for the following configuration from the environment: + +- `TALK_FACEBOOK_APP_ID` (*required*) - the Facebook app id for your Facebook +Login enabled app. +- `TALK_FACEBOOK_APP_SECRET` (*required*) - the Facebook app secret for your +Facebook Login enabled app. + +### License + + Copyright 2016 Mozilla Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + See the License for the specific language governing permissions and limitations under the License. diff --git a/plugins/coral-plugin-facebook-auth/index.js b/plugins/coral-plugin-facebook-auth/index.js new file mode 100644 index 000000000..3e7c61452 --- /dev/null +++ b/plugins/coral-plugin-facebook-auth/index.js @@ -0,0 +1,7 @@ +const passport = require('./server/passport'); +const router = require('./server/router'); + +module.exports = { + passport, + router +}; diff --git a/plugins/coral-plugin-facebook-auth/package.json b/plugins/coral-plugin-facebook-auth/package.json new file mode 100644 index 000000000..ae6721ee9 --- /dev/null +++ b/plugins/coral-plugin-facebook-auth/package.json @@ -0,0 +1,9 @@ +{ + "name": "coral-plugin-facebook-auth", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "passport-facebook": "^2.1.1" + } +} diff --git a/plugins/coral-plugin-facebook-auth/server/passport.js b/plugins/coral-plugin-facebook-auth/server/passport.js new file mode 100644 index 000000000..ae69ec4bd --- /dev/null +++ b/plugins/coral-plugin-facebook-auth/server/passport.js @@ -0,0 +1,27 @@ +const FacebookStrategy = require('passport-facebook').Strategy; +const UsersService = require('services/users'); +const {ValidateUserLogin} = require('services/passport'); + +module.exports = (passport) => { + if (process.env.TALK_FACEBOOK_APP_ID && process.env.TALK_FACEBOOK_APP_SECRET && process.env.TALK_ROOT_URL) { + passport.use(new FacebookStrategy({ + clientID: process.env.TALK_FACEBOOK_APP_ID, + clientSecret: process.env.TALK_FACEBOOK_APP_SECRET, + callbackURL: `${process.env.TALK_ROOT_URL}/api/v1/auth/facebook/callback`, + passReqToCallback: true, + profileFields: ['id', 'displayName', 'picture.type(large)'] + }, async (req, accessToken, refreshToken, profile, done) => { + + let user; + try { + user = await UsersService.findOrCreateExternalUser(profile); + } catch (err) { + return done(err); + } + + return ValidateUserLogin(profile, user, done); + })); + } else if (process.env.NODE_ENV !== 'test') { + throw new Error('Facebook cannot be enabled, missing one of TALK_FACEBOOK_APP_ID, TALK_FACEBOOK_APP_SECRET, TALK_ROOT_URL'); + } +}; diff --git a/plugins/coral-plugin-facebook-auth/server/router.js b/plugins/coral-plugin-facebook-auth/server/router.js new file mode 100644 index 000000000..49d92449e --- /dev/null +++ b/plugins/coral-plugin-facebook-auth/server/router.js @@ -0,0 +1,20 @@ +module.exports = (router) => { + + const {passport, HandleAuthPopupCallback} = require('services/passport'); + + /** + * Facebook auth endpoint, this will redirect the user immediatly to facebook + * for authorization. + */ + router.get('/facebook', passport.authenticate('facebook', {display: 'popup', authType: 'rerequest', scope: ['public_profile']})); + + /** + * Facebook callback endpoint, this will send the user a html page designed to + * send back the user credentials upon sucesfull login. + */ + router.get('/facebook/callback', (req, res, next) => { + + // Perform the facebook login flow and pass the data back through the opener. + passport.authenticate('facebook', HandleAuthPopupCallback(req, res, next))(req, res, next); + }); +}; diff --git a/plugins/coral-plugin-facebook-auth/yarn.lock b/plugins/coral-plugin-facebook-auth/yarn.lock new file mode 100644 index 000000000..a2886dfbe --- /dev/null +++ b/plugins/coral-plugin-facebook-auth/yarn.lock @@ -0,0 +1,34 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +oauth@0.9.x: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + +passport-facebook@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/passport-facebook/-/passport-facebook-2.1.1.tgz#c39d0b52ae4d59163245a4e21a7b9b6321303311" + dependencies: + passport-oauth2 "1.x.x" + +passport-oauth2@1.x.x: + version "1.4.0" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.4.0.tgz#f62f81583cbe12609be7ce6f160b9395a27b86ad" + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-strategy@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + +uid2@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" + +utils-merge@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" diff --git a/routes/api/auth/index.js b/routes/api/auth/index.js index 12a3e8bbe..4926192de 100644 --- a/routes/api/auth/index.js +++ b/routes/api/auth/index.js @@ -1,5 +1,5 @@ const express = require('express'); -const {passport, HandleAuthCallback, HandleAuthPopupCallback} = require('../../../services/passport'); +const {passport, HandleAuthCallback} = require('../../../services/passport'); const authorization = require('../../../middleware/authorization'); const router = express.Router(); @@ -42,20 +42,4 @@ router.post('/local', (req, res, next) => { passport.authenticate('local', HandleAuthCallback(req, res, next))(req, res, next); }); -/** - * Facebook auth endpoint, this will redirect the user immediatly to facebook - * for authorization. - */ -router.get('/facebook', passport.authenticate('facebook', {display: 'popup', authType: 'rerequest', scope: ['public_profile']})); - -/** - * Facebook callback endpoint, this will send the user a html page designed to - * send back the user credentials upon sucesfull login. - */ -router.get('/facebook/callback', (req, res, next) => { - - // Perform the facebook login flow and pass the data back through the opener. - passport.authenticate('facebook', HandleAuthPopupCallback(req, res, next))(req, res, next); -}); - module.exports = router; diff --git a/services/passport.js b/services/passport.js index 09ded01e8..682d86ce1 100644 --- a/services/passport.js +++ b/services/passport.js @@ -4,10 +4,8 @@ const SettingsService = require('./settings'); const fetch = require('node-fetch'); const FormData = require('form-data'); const LocalStrategy = require('passport-local').Strategy; -const FacebookStrategy = require('passport-facebook').Strategy; const errors = require('../errors'); const debug = require('debug')('talk:passport'); -const plugins = require('./plugins'); //============================================================================== // SESSION SERIALIZATION @@ -354,37 +352,6 @@ passport.use(new LocalStrategy({ return ValidateUserLogin(loginProfile, user, done); })); -if (process.env.TALK_FACEBOOK_APP_ID && process.env.TALK_FACEBOOK_APP_SECRET && process.env.TALK_ROOT_URL) { - passport.use(new FacebookStrategy({ - clientID: process.env.TALK_FACEBOOK_APP_ID, - clientSecret: process.env.TALK_FACEBOOK_APP_SECRET, - callbackURL: `${process.env.TALK_ROOT_URL}/api/v1/auth/facebook/callback`, - passReqToCallback: true, - profileFields: ['id', 'displayName', 'picture.type(large)'] - }, async (req, accessToken, refreshToken, profile, done) => { - - let user; - try { - user = await UsersService.findOrCreateExternalUser(profile); - } catch (err) { - return done(err); - } - - return ValidateUserLogin(profile, user, done); - })); -} else { - console.error('Facebook cannot be enabled, missing one of TALK_FACEBOOK_APP_ID, TALK_FACEBOOK_APP_SECRET, TALK_ROOT_URL'); -} - -// Inject server route plugins. -plugins.get('server', 'passport').forEach((plugin) => { - debug(`added plugin '${plugin.plugin.name}'`); - - // Pass the passport.js instance to the plugin to allow it to inject it's - // functionality. - plugin.passport(passport); -}); - module.exports = { passport, ValidateUserLogin, diff --git a/yarn.lock b/yarn.lock index a0420ab91..c9e0c2463 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5372,10 +5372,6 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -oauth@0.9.x: - version "0.9.15" - resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" - object-assign@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" @@ -5589,27 +5585,12 @@ parseurl@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" -passport-facebook@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/passport-facebook/-/passport-facebook-2.1.1.tgz#c39d0b52ae4d59163245a4e21a7b9b6321303311" - dependencies: - passport-oauth2 "1.x.x" - passport-local@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" dependencies: passport-strategy "1.x.x" -passport-oauth2@1.x.x: - version "1.4.0" - resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.4.0.tgz#f62f81583cbe12609be7ce6f160b9395a27b86ad" - dependencies: - oauth "0.9.x" - passport-strategy "1.x.x" - uid2 "0.0.x" - utils-merge "1.x.x" - passport-strategy@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" @@ -7782,10 +7763,6 @@ uid-safe@2.1.3, uid-safe@~2.1.3: base64-url "1.3.3" random-bytes "~1.0.0" -uid2@0.0.x: - version "0.0.3" - resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" - undefsafe@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f" @@ -7855,7 +7832,7 @@ util@0.10.3, util@^0.10.3: dependencies: inherits "2.0.1" -utils-merge@1.0.0, utils-merge@1.x.x: +utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" From 21eb532c6e9468df2a3e8abb3fc230ccb7886c90 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 5 Apr 2017 11:49:22 -0600 Subject: [PATCH 2/4] Added postinstall hook --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0201ab75c..3ea18dfcd 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "A commenting platform from The Coral Project. https://coralproject.net", "main": "app.js", "scripts": { + "postinstall": "./bin/cli plugins reconcile --skip-remote", "start": "./bin/cli serve --jobs", "dev-start": "nodemon --config .nodemon.json --exec \"./bin/cli -c .env serve --jobs\"", "build": "NODE_ENV=production webpack --progress -p --config webpack.config.js --bail", From 2bbbf2bbf7df488854460f84806cb8b72fffbc68 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 5 Apr 2017 12:33:24 -0600 Subject: [PATCH 3/4] Fixed bug in plugin --- plugins/coral-plugin-facebook-auth/server/router.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/coral-plugin-facebook-auth/server/router.js b/plugins/coral-plugin-facebook-auth/server/router.js index 49d92449e..7ef7b0ed2 100644 --- a/plugins/coral-plugin-facebook-auth/server/router.js +++ b/plugins/coral-plugin-facebook-auth/server/router.js @@ -6,13 +6,13 @@ module.exports = (router) => { * Facebook auth endpoint, this will redirect the user immediatly to facebook * for authorization. */ - router.get('/facebook', passport.authenticate('facebook', {display: 'popup', authType: 'rerequest', scope: ['public_profile']})); + router.get('/api/v1/auth/facebook', passport.authenticate('facebook', {display: 'popup', authType: 'rerequest', scope: ['public_profile']})); /** * Facebook callback endpoint, this will send the user a html page designed to * send back the user credentials upon sucesfull login. */ - router.get('/facebook/callback', (req, res, next) => { + router.get('/api/v1/auth/facebook/callback', (req, res, next) => { // Perform the facebook login flow and pass the data back through the opener. passport.authenticate('facebook', HandleAuthPopupCallback(req, res, next))(req, res, next); From a270aef42edb1fbb289664dee533998f1eb1127b Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 5 Apr 2017 13:07:56 -0600 Subject: [PATCH 4/4] fixed license --- plugins/coral-plugin-facebook-auth/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/coral-plugin-facebook-auth/README.md b/plugins/coral-plugin-facebook-auth/README.md index 4982ae368..3a0f72c2f 100644 --- a/plugins/coral-plugin-facebook-auth/README.md +++ b/plugins/coral-plugin-facebook-auth/README.md @@ -13,8 +13,6 @@ Facebook Login enabled app. ### License - Copyright 2016 Mozilla Foundation - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at