diff --git a/config/app.js b/config/app.js new file mode 100644 index 00000000..ee07e8b4 --- /dev/null +++ b/config/app.js @@ -0,0 +1,25 @@ +require('dotenv').config(); + +const oauthUrl = process.env.OAUTH_URL || 'https://hydra.faforever.com' + +const appConfig = { + nodeEnv: process.env.NODE_ENV || 'production', + expressPort: process.env.PORT || '3000', + host: process.env.HOST || 'http://localhost', + session: { + key: process.env.SESSION_SECRET_KEY || '12345', + tokenLifespan: process.env.TOKEN_LIFESPAN || 43200 + }, + oauth: { + clientId: process.env.OAUTH_CLIENT_ID || '12345', + clientSecret: process.env.OAUTH_CLIENT_SECRET || '12345', + url: oauthUrl, + publicUrl: process.env.OAUTH_PUBLIC_URL || oauthUrl, + callback: process.env.CALLBACK || 'callback', + }, + apiUrl: process.env.API_URL || 'https://api.faforever.com', + extractorInterval: process.env.EXTRACTOR_INTERVAL || 5, + playerCountInterval: process.env.PLAYER_COUNT_INTERVAL || 15 +} + +module.exports = appConfig diff --git a/express.js b/express.js index 310938ff..5461a769 100644 --- a/express.js +++ b/express.js @@ -1,33 +1,19 @@ +const appConfig = require('./config/app') const express = require('express'); const showdown = require('showdown'); -const request = require('request'); const passport = require('passport'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const flash = require('connect-flash'); const fs = require('fs'); -let OidcStrategy = require('passport-openidconnect'); const middleware = require('./routes/middleware'); -const cors = require('cors'); const app = express(); const newsRouter = require('./routes/views/news'); +const authRouter = require('./routes/views/auth'); app.locals.clanInvitations = {}; -require('dotenv').config(); -//Define environment variables with default values -process.env.NODE_ENV = process.env.NODE_ENV || 'production'; -process.env.PORT = process.env.PORT || '3000'; -process.env.CALLBACK = process.env.CALLBACK || 'callback'; -process.env.OAUTH_URL = process.env.OAUTH_URL || 'https://hydra.faforever.com'; -process.env.OAUTH_PUBLIC_URL = process.env.OAUTH_PUBLIC_URL || process.env.OAUTH_URL; -process.env.API_URL = process.env.API_URL || 'https://api.faforever.com'; -process.env.OAUTH_CLIENT_ID = process.env.OAUTH_CLIENT_ID || '12345'; -process.env.OAUTH_CLIENT_SECRET = process.env.OAUTH_CLIENT_SECRET || '12345'; -process.env.HOST = process.env.HOST || 'http://localhost'; -process.env.SESSION_SECRET_KEY = process.env.SESSION_SECRET_KEY || '12345'; - //Execute Middleware app.use(middleware.initLocals); app.use(middleware.clientChecks); @@ -46,11 +32,11 @@ app.use(cookieParser()); // Session determines how long will the user be logged in/authorized in the website app.use(session({ - secret: process.env.SESSION_SECRET_KEY, + secret: appConfig.session.key, resave: false, saveUninitialized: false, cookie: { - maxAge: process.env.TOKEN_LIFESPAN * 1000 + maxAge: appConfig.session.tokenLifespan * 1000 } })); @@ -63,7 +49,7 @@ app.use(middleware.flashMessage); //Initialize values for default configs app.set('views', 'templates/views'); app.set('view engine', 'pug'); -app.set('port', process.env.PORT); +app.set('port', appConfig.expressPort); app.use(function(req, res, next){ res.locals.message = req.flash(); @@ -84,20 +70,15 @@ function loggedIn(req, res, next) { } } - - - - //Start and listen on port -app.listen(process.env.PORT, () => { - console.log(`Express listening on port ${process.env.PORT}`); -}); + // --- R O U T E S --- // when the website is asked to render "/pageName" it will come here and see what are the "instructions" to render said page. If the page isn't here, then the website won't render it properly. -app.use("/news", newsRouter) +app.use('/news', newsRouter) +app.use('/', authRouter) // --- UNPROTECTED ROUTES --- const appGetRouteArray = [ @@ -221,76 +202,6 @@ app.get('/client', (req, res) => { }); -app.get('/logout', function (req, res, next) { - req.logout(function (err) { - if (err) { - return next(err); - } - res.redirect('/'); - }); -}); - -// Login and Login/redirect routes -app.get('/login', passport.authenticate('faforever')); - - - -passport.use('faforever', new OidcStrategy({ - issuer: process.env.OAUTH_URL + '/', - tokenURL: process.env.OAUTH_URL + '/oauth2/token', - authorizationURL: process.env.OAUTH_PUBLIC_URL + '/oauth2/auth', - userInfoURL: process.env.OAUTH_URL + '/userinfo?schema=openid', - clientID: process.env.OAUTH_CLIENT_ID, - clientSecret: process.env.OAUTH_CLIENT_SECRET, - callbackURL: `${process.env.HOST}/${process.env.CALLBACK}`, - scope: ['openid', 'public_profile', 'write_account_data'] - }, function (iss, sub, profile, jwtClaims, accessToken, refreshToken, params, verified) { - - request.get( - {url: process.env.API_URL + '/me', headers: {'Authorization': 'Bearer ' + accessToken}}, - function (e, r, body) { - try { - if (r.statusCode !== 200) { - return verified(null); - } - let user = JSON.parse(body); - - user.data.attributes.token = accessToken; - user.data.id = user.data.attributes.userId; - - - return verified(null, user); - } catch (e) { - console.log(e); - return verified(null, null); - } - - } - ); - } -)); - - -passport.serializeUser(function (user, done) { - - done(null, user); - -}); - -passport.deserializeUser(function (user, done) { - done(null, user); -}); - - -app.get(`/${process.env.CALLBACK}`, passport.authenticate('faforever', { - failureRedirect: '/login', // Failed auth - failureFlash: true -}), function (req, res) { - res.redirect('/'); - //res.redirect(fullUrl ? fullUrl : '/'); - //fullUrl = '/'; // Successful auth -}); - // Run scripts initially on startup let requireRunArray = ['extractor']; for (let i = 0; i < requireRunArray.length; i++) { @@ -306,7 +217,7 @@ for (let i = 0; i < requireRunArray.length; i++) { } catch (e) { console.error(`${requireRunArray[i]} caused the error`, e); } - }, process.env.EXTRACTOR_INTERVAL * 60 * 1000); + }, appConfig.extractorInterval * 60 * 1000); } setInterval(() => { try { @@ -315,7 +226,7 @@ setInterval(() => { } catch (e) { console.error(`getRecentUsers script caused the error`, e); } -}, process.env.PLAYER_COUNT_INTERVAL * 1000); +}, appConfig.playerCountInterval * 1000); //404 Error Handlers @@ -330,4 +241,7 @@ app.use(function (err, req, res, next) { res.status(500).render('errors/500'); }); - + +app.listen(appConfig.expressPort, () => { + console.log(`Express listening on port ${appConfig.expressPort}`); +}); diff --git a/package.json b/package.json index 37b8eb84..b7c88678 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "client-oauth2": "4.3.3", "connect-flash": "^0.1.1", "cookie-parser": "^1.4.6", - "cors": "^2.8.5", "dotenv": "16.3.1", "express": "^4.18.1", "express-session": "^1.17.3", diff --git a/routes/views/auth.js b/routes/views/auth.js new file mode 100644 index 00000000..9957ce14 --- /dev/null +++ b/routes/views/auth.js @@ -0,0 +1,58 @@ +const appConfig = require('../../config/app') +const passport = require('passport'); +const OidcStrategy = require('passport-openidconnect'); +const express = require("express"); +const axios = require("axios"); +const router = express.Router(); + +passport.serializeUser((user, done) => done(null, user)) +passport.deserializeUser((user, done) => done(null, user)) + +passport.use('faforever', new OidcStrategy({ + issuer: appConfig.oauth.url + '/', + tokenURL: appConfig.oauth.url + '/oauth2/token', + authorizationURL: appConfig.oauth.publicUrl + '/oauth2/auth', + userInfoURL: appConfig.oauth.url + '/userinfo?schema=openid', + clientID: appConfig.oauth.clientId, + clientSecret: appConfig.oauth.clientSecret, + callbackURL: `${appConfig.host}/${appConfig.oauth.callback}`, + scope: ['openid', 'public_profile', 'write_account_data'] + }, function (iss, sub, profile, jwtClaims, accessToken, refreshToken, params, verified) { + + axios.get( + appConfig.apiUrl + '/me', + { + headers: {'Authorization': `Bearer ${accessToken}`} + }).then((res) => { + const user = res.data + user.token = accessToken + user.data.attributes.token = accessToken; + user.data.id = user.data.attributes.userId; + + return verified(null, user); + }).catch(e => { + console.error('[Error] views/auth.js::passport::verify failed with "' + e.toString() + '"'); + + return verified(null, null); + }); + } +)); + +router.get('/login', passport.authenticate('faforever')); + +router.get( + '/' + appConfig.oauth.callback, + passport.authenticate('faforever', {failureRedirect: '/login', failureFlash: true}), + (req, res) => res.redirect('/') +) + +router.get('/logout', (req, res, next) => { + req.logout((err) => { + if (err) { + return next(err) + } + res.redirect('/') + }) +}) + +module.exports = router diff --git a/yarn.lock b/yarn.lock index 6af508b1..ce71f0f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1186,14 +1186,6 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@^2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - cosmiconfig@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -3801,7 +3793,7 @@ oauth@0.9.x: resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" integrity sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA== -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -5772,7 +5764,7 @@ validator@^13.9.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== -vary@^1, vary@~1.1.2: +vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==