diff --git a/packages/user/package.json b/packages/user/package.json index 3fe5781..1d19aaa 100644 --- a/packages/user/package.json +++ b/packages/user/package.json @@ -28,7 +28,9 @@ "@reduxjs/toolkit": "^1.5.0", "connected-react-router": "^6.8.0", "debug": "4.3.1", - "deepmerge": "^4.2.2" + "deepmerge": "^4.2.2", + "passport": "^0.4.1", + "passport-reddit": "^0.2.4" }, "devDependencies": { "@neutrinojs/airbnb-base": "^9.4.0", diff --git a/packages/user/src/index.js b/packages/user/src/index.js index 2f13754..daaece3 100644 --- a/packages/user/src/index.js +++ b/packages/user/src/index.js @@ -1,3 +1,10 @@ +import {randomBytes} from 'crypto'; + +import {ModelMap} from '@latus/db'; +import {renderChannel} from '@reddichat/core'; +import passport from 'passport'; +import {Strategy as RedditStrategy} from 'passport-reddit'; + import UserReddichat from './models/user-reddichat'; import AddFavorite from './packets/add-favorite.server'; import AddFriend from './packets/add-friend.server'; @@ -11,12 +18,94 @@ import Usernames from './packets/usernames.server'; import userDefaultState from './state/user'; import usernamesDefaultState from './state/usernames'; +const { + REDDIT_CALLBACK_URL, + REDDIT_CLIENT_ID, + REDDIT_CLIENT_SECRET, +} = process.env; + export default { hooks: { + '@latus/core/up': (latus) => { + passport.use(new RedditStrategy( + { + clientID: REDDIT_CLIENT_ID, + clientSecret: REDDIT_CLIENT_SECRET, + callbackURL: REDDIT_CALLBACK_URL, + }, + async (accessToken, refreshToken, profile, done) => { + const {User} = ModelMap(latus); + try { + const where = {redditUsername: profile.name}; + const user = await User.findOne({where}) || await User.create(where); + user.redditAccessToken = accessToken; + if (user.isNewRecord) { + await user.createFavorite({channel: '/r/reddichat'}); + } + await user.save(); + done(undefined, user); + } + catch (error) { + done(error); + } + }, + )); + }, '@latus/db/models.decorate': (Models, latus) => ({ ...Models, User: UserReddichat(Models.User, latus), }), + '@latus/http/routes': () => [ + { + method: 'get', + path: '/auth/reddit', + handler: (req, res, next) => { + req.session.state = randomBytes(32).toString('hex'); + passport.authenticate('reddit', {state: req.session.state})(req, res, next); + }, + }, + { + method: 'get', + path: '/auth/reddit/callback', + handler: (req, res, next) => { + if (req.query.state === req.session.state) { + delete req.session.state; + req.session.save((error) => { + if (error) { + next(error); + return; + } + passport.authenticate('reddit', (error, user) => { + if (error) { + next(error); + return; + } + if (!user) { + res.redirect('/'); + } + req.login(user, async (error) => { + if (error) { + next(error); + return; + } + const favorites = await user.favorites(); + const channels = favorites.filter(({type}) => 'r' === type); + if (channels.length > 0) { + res.redirect(`/chat${renderChannel(channels[0])}`); + } + else { + res.redirect('/chat'); + } + }); + })(req, res, next); + }); + } + else { + res.status(403).end('Forbidden: state mismatch'); + } + }, + }, + ], '@latus/socket/packets': (latus) => ({ AddFavorite: AddFavorite(latus), AddFriend: AddFriend(latus), diff --git a/packages/user/yarn.lock b/packages/user/yarn.lock index d0f608b..9d81017 100644 --- a/packages/user/yarn.lock +++ b/packages/user/yarn.lock @@ -1849,6 +1849,11 @@ base64id@2.0.0: resolved "https://npm.i12e.cha0s.io/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== +base64url@3.x.x: + version "3.0.1" + resolved "https://npm.i12e.cha0s.io/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + base@^0.11.1: version "0.11.2" resolved "https://npm.i12e.cha0s.io/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -5878,6 +5883,11 @@ oauth-sign@~0.9.0: resolved "https://npm.i12e.cha0s.io/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +oauth@0.9.x: + version "0.9.15" + resolved "https://npm.i12e.cha0s.io/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= + object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://npm.i12e.cha0s.io/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -6235,6 +6245,55 @@ pascalcase@^0.1.1: resolved "https://npm.i12e.cha0s.io/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +passport-oauth1@1.x.x: + version "1.1.0" + resolved "https://npm.i12e.cha0s.io/passport-oauth1/-/passport-oauth1-1.1.0.tgz#a7de988a211f9cf4687377130ea74df32730c918" + integrity sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg= + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + utils-merge "1.x.x" + +passport-oauth2@1.x.x: + version "1.5.0" + resolved "https://npm.i12e.cha0s.io/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108" + integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ== + dependencies: + base64url "3.x.x" + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-oauth@1.x: + version "1.0.0" + resolved "https://npm.i12e.cha0s.io/passport-oauth/-/passport-oauth-1.0.0.tgz#90aff63387540f02089af28cdad39ea7f80d77df" + integrity sha1-kK/2M4dUDwIImvKM2tOep/gNd98= + dependencies: + passport-oauth1 "1.x.x" + passport-oauth2 "1.x.x" + +passport-reddit@^0.2.4: + version "0.2.4" + resolved "https://npm.i12e.cha0s.io/passport-reddit/-/passport-reddit-0.2.4.tgz#4e5805d919a8f28f80c238f7da2d92a38067acc5" + integrity sha1-TlgF2Rmo8o+Awjj32i2So4BnrMU= + dependencies: + passport-oauth "1.x" + pkginfo "0.3.x" + +passport-strategy@1.x.x: + version "1.0.0" + resolved "https://npm.i12e.cha0s.io/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= + +passport@^0.4.1: + version "0.4.1" + resolved "https://npm.i12e.cha0s.io/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + path-browserify@0.0.1: version "0.0.1" resolved "https://npm.i12e.cha0s.io/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" @@ -6320,6 +6379,11 @@ pathval@^1.1.0: resolved "https://npm.i12e.cha0s.io/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= +pause@0.0.1: + version "0.0.1" + resolved "https://npm.i12e.cha0s.io/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + pbkdf2@^3.0.3: version "3.1.1" resolved "https://npm.i12e.cha0s.io/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" @@ -6396,6 +6460,11 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" +pkginfo@0.3.x: + version "0.3.1" + resolved "https://npm.i12e.cha0s.io/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" + integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= + portfinder@^1.0.26: version "1.0.28" resolved "https://npm.i12e.cha0s.io/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" @@ -8137,7 +8206,7 @@ uid-safe@~2.1.5: dependencies: random-bytes "~1.0.0" -uid2@0.0.3: +uid2@0.0.3, uid2@0.0.x: version "0.0.3" resolved "https://npm.i12e.cha0s.io/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= @@ -8296,7 +8365,7 @@ utila@~0.4: resolved "https://npm.i12e.cha0s.io/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw= -utils-merge@1.0.1: +utils-merge@1.0.1, utils-merge@1.x.x: version "1.0.1" resolved "https://npm.i12e.cha0s.io/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=