├── .gitignore ├── README.md ├── client ├── package.json ├── public │ ├── index.html │ └── manifest.json ├── src │ ├── App.js │ ├── App.test.js │ ├── AppRouter.js │ ├── components │ │ ├── Header.jsx │ │ └── Homepage.jsx │ ├── images │ │ ├── AppPage.png │ │ ├── demo.gif │ │ ├── keys.png │ │ ├── session.png │ │ └── sign-in-with-twitter-gray.png │ ├── index.css │ ├── index.js │ └── serviceWorker.js └── yarn.lock ├── server ├── config │ ├── keys.copy.js │ └── passport-setup.js ├── index.js ├── models │ └── user-model.js ├── package.json ├── routes │ └── auth-routes.js └── yarn.lock └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /.pnp 5 | .pnp.js 6 | 7 | # testing 8 | /coverage 9 | 10 | # production 11 | /build 12 | /public 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | # client 22 | /client/node_modules 23 | 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # server 29 | /server/config/keys.js 30 | /server/node_modules 31 | /client/build/ 32 | node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Authenticate Twitter via passport 2 | 3 | ### About 4 | 5 | This is a simple web authentication web application via Twitter OAuth. Please feel free to fork this and build your own application. If you have any questions, please feel free to send me an issue or a pull request. 6 | 7 | ### Demo 8 | 9 | ![Demo](client/src/images/demo.gif) 10 | 11 | --- 12 | ### Follow my online tutorial 13 | - https://medium.com/@leannezhang/building-a-web-application-twitter-oauth-using-passport-js-part-1-9ffa6f49ef0 14 | 15 | --- 16 | 17 | ### Server 18 | 19 | Run on express server 20 | 21 | ``` 22 | cd server/ 23 | nodemon index.js 24 | ``` 25 | 26 | Go to localhost:4000 27 | 28 | ### Client 29 | 30 | ``` 31 | cd client/ 32 | yarn install 33 | yarn run start 34 | ``` 35 | 36 | Go to localhost:3000 37 | 38 | ### Instructions 39 | 40 | - Rename `/server/config/keys.copy.js` to `/server/config/keys.js` and add your keys 41 | 42 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitter-authentication", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "prop-types": "^15.6.2", 7 | "react": "^16.7.0", 8 | "react-dom": "^16.7.0", 9 | "react-router-dom": "^5.0.0", 10 | "react-scripts": "2.1.2" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test", 16 | "eject": "react-scripts eject" 17 | }, 18 | "eslintConfig": { 19 | "extends": "react-app" 20 | }, 21 | "browserslist": [ 22 | ">0.2%", 23 | "not dead", 24 | "not ie <= 11", 25 | "not op_mini all" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /client/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { AppRouter } from "./AppRouter"; 3 | 4 | class App extends Component { 5 | render() { 6 | return ; 7 | } 8 | } 9 | 10 | export default App; 11 | -------------------------------------------------------------------------------- /client/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /client/src/AppRouter.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import HomePage from "./components/Homepage"; 3 | import { BrowserRouter as Router, Route } from "react-router-dom"; 4 | 5 | export const AppRouter = () => { 6 | return ( 7 | 8 |
9 | 10 |
11 |
12 | ); 13 | }; 14 | -------------------------------------------------------------------------------- /client/src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import PropTypes from "prop-types"; 3 | import React, { Component } from "react"; 4 | 5 | export default class Header extends Component { 6 | static propTypes = { 7 | authenticated: PropTypes.bool.isRequired 8 | }; 9 | 10 | render() { 11 | const { authenticated } = this.props; 12 | return ( 13 | 23 | ); 24 | } 25 | 26 | _handleSignInClick = () => { 27 | // Authenticate using via passport api in the backend 28 | // Open Twitter login page 29 | // Upon successful login, a cookie session will be stored in the client 30 | window.open("http://localhost:4000/auth/twitter", "_self"); 31 | }; 32 | 33 | _handleLogoutClick = () => { 34 | // Logout using Twitter passport api 35 | // Set authenticated state to false in the HomePage 36 | window.open("http://localhost:4000/auth/logout", "_self"); 37 | this.props.handleNotAuthenticated(); 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /client/src/components/Homepage.jsx: -------------------------------------------------------------------------------- 1 | import Header from "./Header"; 2 | import PropTypes from "prop-types"; 3 | import React, { Component } from "react"; 4 | 5 | export default class HomePage extends Component { 6 | static propTypes = { 7 | user: PropTypes.shape({ 8 | name: PropTypes.string, 9 | profileImageUrl: PropTypes.string, 10 | twitterId: PropTypes.string, 11 | screenName: PropTypes.string, 12 | _id: PropTypes.string 13 | }) 14 | }; 15 | 16 | state = { 17 | user: {}, 18 | error: null, 19 | authenticated: false 20 | }; 21 | 22 | componentDidMount() { 23 | // Fetch does not send cookies. So you should add credentials: 'include' 24 | fetch("http://localhost:4000/auth", { 25 | method: "GET", 26 | credentials: "include", 27 | headers: { 28 | Accept: "application/json", 29 | "Content-Type": "application/json", 30 | "Access-Control-Allow-Credentials": true 31 | } 32 | }) 33 | .then(response => { 34 | if (response.status === 200) return response.json(); 35 | throw new Error("failed to authenticate user"); 36 | }) 37 | .then(responseJson => { 38 | this.setState({ 39 | authenticated: true, 40 | user: responseJson.user 41 | }); 42 | }) 43 | .catch(error => { 44 | this.setState({ 45 | authenticated: false, 46 | error: "Failed to authenticate user" 47 | }); 48 | }); 49 | } 50 | 51 | render() { 52 | const { authenticated } = this.state; 53 | return ( 54 |
55 |
59 |
60 | {!authenticated ? ( 61 |

Welcome!

62 | ) : ( 63 |
64 |

You have login succcessfully!

65 |

Welcome {this.state.user.name}!

66 |
67 | )} 68 |
69 |
70 | ); 71 | } 72 | 73 | _handleNotAuthenticated = () => { 74 | this.setState({ authenticated: false }); 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /client/src/images/AppPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leannezhang/twitter-authentication/50355fe039ae149b944b8851493308738bbda0de/client/src/images/AppPage.png -------------------------------------------------------------------------------- /client/src/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leannezhang/twitter-authentication/50355fe039ae149b944b8851493308738bbda0de/client/src/images/demo.gif -------------------------------------------------------------------------------- /client/src/images/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leannezhang/twitter-authentication/50355fe039ae149b944b8851493308738bbda0de/client/src/images/keys.png -------------------------------------------------------------------------------- /client/src/images/session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leannezhang/twitter-authentication/50355fe039ae149b944b8851493308738bbda0de/client/src/images/session.png -------------------------------------------------------------------------------- /client/src/images/sign-in-with-twitter-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leannezhang/twitter-authentication/50355fe039ae149b944b8851493308738bbda0de/client/src/images/sign-in-with-twitter-gray.png -------------------------------------------------------------------------------- /client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | 16 | .menu { 17 | display: flex; 18 | list-style-type: none; 19 | justify-content: flex-end; 20 | } 21 | 22 | .menu li { 23 | margin: 0 10px; 24 | cursor: pointer; 25 | text-decoration: underline; 26 | } 27 | -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /client/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /server/config/keys.copy.js: -------------------------------------------------------------------------------- 1 | // ADD YOUR OWN KEYS AND RENAME THIS FILE TO keys.js 2 | const TWITTER_TOKENS = { 3 | TWITTER_CONSUMER_KEY: "SOME KEY", 4 | TWITTER_CONSUMER_SECRET: "SOME SECRET", 5 | TWITTER_ACCESS_TOKEN: "SOME ACCESS TOKEN", 6 | TWITTER_TOKEN_SECRET: "SOME TOKEN SECRET" 7 | }; 8 | 9 | const DB_USER = "SOME USER"; 10 | const DB_PASSWORD = "SOME PASSWPORD"; 11 | const MONGODB = { 12 | MONGODB_URI: `mongodb://${DB_USER}:${DB_PASSWORD}@ds.mlab.com:/` 13 | }; 14 | 15 | const SESSION = { 16 | COOKIE_KEY: "thisappisawesome" 17 | }; 18 | 19 | const KEYS = { 20 | ...TWITTER_TOKENS, 21 | ...MONGODB, 22 | ...SESSION 23 | }; 24 | 25 | module.exports = KEYS; 26 | -------------------------------------------------------------------------------- /server/config/passport-setup.js: -------------------------------------------------------------------------------- 1 | const passport = require("passport"); 2 | const TwitterStrategy = require("passport-twitter"); 3 | const keys = require("./keys"); 4 | const User = require("../models/user-model"); 5 | 6 | // serialize the user.id to save in the cookie session 7 | // so the browser will remember the user when login 8 | passport.serializeUser((user, done) => { 9 | done(null, user.id); 10 | }); 11 | 12 | // deserialize the cookieUserId to user in the database 13 | passport.deserializeUser((id, done) => { 14 | User.findById(id) 15 | .then(user => { 16 | done(null, user); 17 | }) 18 | .catch(e => { 19 | done(new Error("Failed to deserialize an user")); 20 | }); 21 | }); 22 | 23 | passport.use( 24 | new TwitterStrategy( 25 | { 26 | consumerKey: keys.TWITTER_CONSUMER_KEY, 27 | consumerSecret: keys.TWITTER_CONSUMER_SECRET, 28 | callbackURL: "/auth/twitter/redirect" 29 | }, 30 | async (token, tokenSecret, profile, done) => { 31 | // find current user in UserModel 32 | const currentUser = await User.findOne({ 33 | twitterId: profile._json.id_str 34 | }); 35 | // create new user if the database doesn't have this user 36 | if (!currentUser) { 37 | const newUser = await new User({ 38 | name: profile._json.name, 39 | screenName: profile._json.screen_name, 40 | twitterId: profile._json.id_str, 41 | profileImageUrl: profile._json.profile_image_url 42 | }).save(); 43 | if (newUser) { 44 | done(null, newUser); 45 | } 46 | } 47 | done(null, currentUser); 48 | } 49 | ) 50 | ); 51 | -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const cookieSession = require("cookie-session"); 2 | const express = require("express"); 3 | const app = express(); 4 | const port = 4000; 5 | const passport = require("passport"); 6 | const passportSetup = require("./config/passport-setup"); 7 | const session = require("express-session"); 8 | const authRoutes = require("./routes/auth-routes"); 9 | const mongoose = require("mongoose"); 10 | const keys = require("./config/keys"); 11 | const cors = require("cors"); 12 | const cookieParser = require("cookie-parser"); // parse cookie header 13 | 14 | // connect to mongodb 15 | mongoose.connect(keys.MONGODB_URI, () => { 16 | console.log("connected to mongo db"); 17 | }); 18 | 19 | app.use( 20 | cookieSession({ 21 | name: "session", 22 | keys: [keys.COOKIE_KEY], 23 | maxAge: 24 * 60 * 60 * 100 24 | }) 25 | ); 26 | 27 | // parse cookies 28 | app.use(cookieParser()); 29 | 30 | // initalize passport 31 | app.use(passport.initialize()); 32 | // deserialize cookie from the browser 33 | app.use(passport.session()); 34 | 35 | // set up cors to allow us to accept requests from our client 36 | app.use( 37 | cors({ 38 | origin: "http://localhost:3000", // allow to server to accept request from different origin 39 | methods: "GET,HEAD,PUT,PATCH,POST,DELETE", 40 | credentials: true // allow session cookie from browser to pass through 41 | }) 42 | ); 43 | 44 | // set up routes 45 | app.use("/auth", authRoutes); 46 | 47 | const authCheck = (req, res, next) => { 48 | if (!req.user) { 49 | res.status(401).json({ 50 | authenticated: false, 51 | message: "user has not been authenticated" 52 | }); 53 | } else { 54 | next(); 55 | } 56 | }; 57 | 58 | // if it's already login, send the profile response, 59 | // otherwise, send a 401 response that the user is not authenticated 60 | // authCheck before navigating to home page 61 | app.get("/", authCheck, (req, res) => { 62 | res.status(200).json({ 63 | authenticated: true, 64 | message: "user successfully authenticated", 65 | user: req.user, 66 | cookies: req.cookies 67 | }); 68 | }); 69 | 70 | // connect react to nodejs express server 71 | app.listen(port, () => console.log(`Server is running on port ${port}!`)); 72 | -------------------------------------------------------------------------------- /server/models/user-model.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Schema = mongoose.Schema; 3 | 4 | const userSchema = new Schema({ 5 | name: String, 6 | screenName: String, 7 | twitterId: String, 8 | profileImageUrl: String 9 | }); 10 | 11 | const User = mongoose.model("user", userSchema); 12 | 13 | module.exports = User; 14 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twitter-oauth", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.18.3", 13 | "cookie-parser": "^1.4.3", 14 | "cookie-session": "^2.0.0-beta.3", 15 | "cors": "^2.8.5", 16 | "express": "^4.16.4", 17 | "express-session": "^1.15.6", 18 | "mongoose": "^5.4.1", 19 | "passport": "^0.4.0", 20 | "passport-twitter": "^1.0.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/routes/auth-routes.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const passport = require("passport"); 3 | const CLIENT_HOME_PAGE_URL = "http://localhost:3000"; 4 | 5 | // when login is successful, retrieve user info 6 | router.get("/login/success", (req, res) => { 7 | if (req.user) { 8 | res.json({ 9 | success: true, 10 | message: "user has successfully authenticated", 11 | user: req.user, 12 | cookies: req.cookies 13 | }); 14 | } 15 | }); 16 | 17 | // when login failed, send failed msg 18 | router.get("/login/failed", (req, res) => { 19 | res.status(401).json({ 20 | success: false, 21 | message: "user failed to authenticate." 22 | }); 23 | }); 24 | 25 | // When logout, redirect to client 26 | router.get("/logout", (req, res) => { 27 | req.logout(); 28 | res.redirect(CLIENT_HOME_PAGE_URL); 29 | }); 30 | 31 | // auth with twitter 32 | router.get("/twitter", passport.authenticate("twitter")); 33 | 34 | // redirect to home page after successfully login via twitter 35 | router.get( 36 | "/twitter/redirect", 37 | passport.authenticate("twitter", { 38 | successRedirect: CLIENT_HOME_PAGE_URL, 39 | failureRedirect: "/auth/login/failed" 40 | }) 41 | ); 42 | 43 | module.exports = router; 44 | -------------------------------------------------------------------------------- /server/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.5: 6 | version "1.3.5" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" 8 | integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= 9 | dependencies: 10 | mime-types "~2.1.18" 11 | negotiator "0.6.1" 12 | 13 | array-flatten@1.1.1: 14 | version "1.1.1" 15 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 16 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 17 | 18 | bluebird@3.5.1: 19 | version "3.5.1" 20 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" 21 | integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== 22 | 23 | body-parser@1.18.3, body-parser@^1.18.3: 24 | version "1.18.3" 25 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" 26 | integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= 27 | dependencies: 28 | bytes "3.0.0" 29 | content-type "~1.0.4" 30 | debug "2.6.9" 31 | depd "~1.1.2" 32 | http-errors "~1.6.3" 33 | iconv-lite "0.4.23" 34 | on-finished "~2.3.0" 35 | qs "6.5.2" 36 | raw-body "2.3.3" 37 | type-is "~1.6.16" 38 | 39 | bson@^1.1.1, bson@~1.1.1: 40 | version "1.1.1" 41 | resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.1.tgz#4330f5e99104c4e751e7351859e2d408279f2f13" 42 | integrity sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg== 43 | 44 | bytes@3.0.0: 45 | version "3.0.0" 46 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 47 | integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= 48 | 49 | content-disposition@0.5.2: 50 | version "0.5.2" 51 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 52 | integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= 53 | 54 | content-type@~1.0.4: 55 | version "1.0.4" 56 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 57 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 58 | 59 | cookie-parser@^1.4.3: 60 | version "1.4.3" 61 | resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.3.tgz#0fe31fa19d000b95f4aadf1f53fdc2b8a203baa5" 62 | integrity sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU= 63 | dependencies: 64 | cookie "0.3.1" 65 | cookie-signature "1.0.6" 66 | 67 | cookie-session@^2.0.0-beta.3: 68 | version "2.0.0-beta.3" 69 | resolved "https://registry.yarnpkg.com/cookie-session/-/cookie-session-2.0.0-beta.3.tgz#4e446bd9f85bd7e27d3e226f4e99af12011a4386" 70 | integrity sha512-zyqm5tA0z9yMEB/xyP7lnRnqp8eLR2e0dap+9+rBwVigla9yPKn8XTL1jJymog8xjfrowqW2o5LUjixQChkqrw== 71 | dependencies: 72 | cookies "0.7.1" 73 | debug "3.1.0" 74 | on-headers "~1.0.1" 75 | safe-buffer "5.1.1" 76 | 77 | cookie-signature@1.0.6: 78 | version "1.0.6" 79 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 80 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 81 | 82 | cookie@0.3.1: 83 | version "0.3.1" 84 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 85 | integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= 86 | 87 | cookies@0.7.1: 88 | version "0.7.1" 89 | resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" 90 | integrity sha1-fIphX1SBxhq58WyDNzG8uPZjuZs= 91 | dependencies: 92 | depd "~1.1.1" 93 | keygrip "~1.0.2" 94 | 95 | cors@^2.8.5: 96 | version "2.8.5" 97 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" 98 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== 99 | dependencies: 100 | object-assign "^4" 101 | vary "^1" 102 | 103 | crc@3.4.4: 104 | version "3.4.4" 105 | resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b" 106 | integrity sha1-naHpgOO9RPxck79as9ozeNheRms= 107 | 108 | debug@2.6.9: 109 | version "2.6.9" 110 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 111 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 112 | dependencies: 113 | ms "2.0.0" 114 | 115 | debug@3.1.0: 116 | version "3.1.0" 117 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 118 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 119 | dependencies: 120 | ms "2.0.0" 121 | 122 | depd@~1.1.1, depd@~1.1.2: 123 | version "1.1.2" 124 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 125 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 126 | 127 | destroy@~1.0.4: 128 | version "1.0.4" 129 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 130 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 131 | 132 | ee-first@1.1.1: 133 | version "1.1.1" 134 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 135 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 136 | 137 | encodeurl@~1.0.2: 138 | version "1.0.2" 139 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 140 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 141 | 142 | escape-html@~1.0.3: 143 | version "1.0.3" 144 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 145 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 146 | 147 | etag@~1.8.1: 148 | version "1.8.1" 149 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 150 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 151 | 152 | express-session@^1.15.6: 153 | version "1.15.6" 154 | resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.15.6.tgz#47b4160c88f42ab70fe8a508e31cbff76757ab0a" 155 | integrity sha512-r0nrHTCYtAMrFwZ0kBzZEXa1vtPVrw0dKvGSrKP4dahwBQ1BJpF2/y1Pp4sCD/0kvxV4zZeclyvfmw0B4RMJQA== 156 | dependencies: 157 | cookie "0.3.1" 158 | cookie-signature "1.0.6" 159 | crc "3.4.4" 160 | debug "2.6.9" 161 | depd "~1.1.1" 162 | on-headers "~1.0.1" 163 | parseurl "~1.3.2" 164 | uid-safe "~2.1.5" 165 | utils-merge "1.0.1" 166 | 167 | express@^4.16.4: 168 | version "4.16.4" 169 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" 170 | integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== 171 | dependencies: 172 | accepts "~1.3.5" 173 | array-flatten "1.1.1" 174 | body-parser "1.18.3" 175 | content-disposition "0.5.2" 176 | content-type "~1.0.4" 177 | cookie "0.3.1" 178 | cookie-signature "1.0.6" 179 | debug "2.6.9" 180 | depd "~1.1.2" 181 | encodeurl "~1.0.2" 182 | escape-html "~1.0.3" 183 | etag "~1.8.1" 184 | finalhandler "1.1.1" 185 | fresh "0.5.2" 186 | merge-descriptors "1.0.1" 187 | methods "~1.1.2" 188 | on-finished "~2.3.0" 189 | parseurl "~1.3.2" 190 | path-to-regexp "0.1.7" 191 | proxy-addr "~2.0.4" 192 | qs "6.5.2" 193 | range-parser "~1.2.0" 194 | safe-buffer "5.1.2" 195 | send "0.16.2" 196 | serve-static "1.13.2" 197 | setprototypeof "1.1.0" 198 | statuses "~1.4.0" 199 | type-is "~1.6.16" 200 | utils-merge "1.0.1" 201 | vary "~1.1.2" 202 | 203 | finalhandler@1.1.1: 204 | version "1.1.1" 205 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" 206 | integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== 207 | dependencies: 208 | debug "2.6.9" 209 | encodeurl "~1.0.2" 210 | escape-html "~1.0.3" 211 | on-finished "~2.3.0" 212 | parseurl "~1.3.2" 213 | statuses "~1.4.0" 214 | unpipe "~1.0.0" 215 | 216 | forwarded@~0.1.2: 217 | version "0.1.2" 218 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 219 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 220 | 221 | fresh@0.5.2: 222 | version "0.5.2" 223 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 224 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 225 | 226 | http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: 227 | version "1.6.3" 228 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" 229 | integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= 230 | dependencies: 231 | depd "~1.1.2" 232 | inherits "2.0.3" 233 | setprototypeof "1.1.0" 234 | statuses ">= 1.4.0 < 2" 235 | 236 | iconv-lite@0.4.23: 237 | version "0.4.23" 238 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" 239 | integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== 240 | dependencies: 241 | safer-buffer ">= 2.1.2 < 3" 242 | 243 | inherits@2.0.3: 244 | version "2.0.3" 245 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 246 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 247 | 248 | ipaddr.js@1.8.0: 249 | version "1.8.0" 250 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" 251 | integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= 252 | 253 | kareem@2.3.1: 254 | version "2.3.1" 255 | resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" 256 | integrity sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw== 257 | 258 | keygrip@~1.0.2: 259 | version "1.0.3" 260 | resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.3.tgz#399d709f0aed2bab0a059e0cdd3a5023a053e1dc" 261 | integrity sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g== 262 | 263 | media-typer@0.3.0: 264 | version "0.3.0" 265 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 266 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 267 | 268 | merge-descriptors@1.0.1: 269 | version "1.0.1" 270 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 271 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 272 | 273 | methods@~1.1.2: 274 | version "1.1.2" 275 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 276 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 277 | 278 | mime-db@~1.37.0: 279 | version "1.37.0" 280 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" 281 | integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== 282 | 283 | mime-types@~2.1.18: 284 | version "2.1.21" 285 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" 286 | integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== 287 | dependencies: 288 | mime-db "~1.37.0" 289 | 290 | mime@1.4.1: 291 | version "1.4.1" 292 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" 293 | integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== 294 | 295 | mongodb@3.3.2: 296 | version "3.3.2" 297 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.3.2.tgz#ff086b5f552cf07e24ce098694210f3d42d668b2" 298 | integrity sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg== 299 | dependencies: 300 | bson "^1.1.1" 301 | require_optional "^1.0.1" 302 | safe-buffer "^5.1.2" 303 | 304 | mongoose-legacy-pluralize@1.0.2: 305 | version "1.0.2" 306 | resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" 307 | integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== 308 | 309 | mongoose@^5.4.1: 310 | version "5.7.5" 311 | resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.7.5.tgz#b787b47216edf62036aa358c3ef0f1869c46cdc2" 312 | integrity sha512-BZ4FxtnbTurc/wcm/hLltLdI4IDxo4nsE0D9q58YymTdZwreNzwO62CcjVtaHhmr8HmJtOInp2W/T12FZaMf8g== 313 | dependencies: 314 | bson "~1.1.1" 315 | kareem "2.3.1" 316 | mongodb "3.3.2" 317 | mongoose-legacy-pluralize "1.0.2" 318 | mpath "0.6.0" 319 | mquery "3.2.2" 320 | ms "2.1.2" 321 | regexp-clone "1.0.0" 322 | safe-buffer "5.1.2" 323 | sift "7.0.1" 324 | sliced "1.0.1" 325 | 326 | mpath@0.6.0: 327 | version "0.6.0" 328 | resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.6.0.tgz#aa922029fca4f0f641f360e74c5c1b6a4c47078e" 329 | integrity sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw== 330 | 331 | mquery@3.2.2: 332 | version "3.2.2" 333 | resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.2.tgz#e1383a3951852ce23e37f619a9b350f1fb3664e7" 334 | integrity sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q== 335 | dependencies: 336 | bluebird "3.5.1" 337 | debug "3.1.0" 338 | regexp-clone "^1.0.0" 339 | safe-buffer "5.1.2" 340 | sliced "1.0.1" 341 | 342 | ms@2.0.0: 343 | version "2.0.0" 344 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 345 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 346 | 347 | ms@2.1.2: 348 | version "2.1.2" 349 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 350 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 351 | 352 | negotiator@0.6.1: 353 | version "0.6.1" 354 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 355 | integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= 356 | 357 | oauth@0.9.x: 358 | version "0.9.15" 359 | resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" 360 | integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= 361 | 362 | object-assign@^4: 363 | version "4.1.1" 364 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 365 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 366 | 367 | on-finished@~2.3.0: 368 | version "2.3.0" 369 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 370 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 371 | dependencies: 372 | ee-first "1.1.1" 373 | 374 | on-headers@~1.0.1: 375 | version "1.0.1" 376 | resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" 377 | integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c= 378 | 379 | parseurl@~1.3.2: 380 | version "1.3.2" 381 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" 382 | integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= 383 | 384 | passport-oauth1@1.x.x: 385 | version "1.1.0" 386 | resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.1.0.tgz#a7de988a211f9cf4687377130ea74df32730c918" 387 | integrity sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg= 388 | dependencies: 389 | oauth "0.9.x" 390 | passport-strategy "1.x.x" 391 | utils-merge "1.x.x" 392 | 393 | passport-strategy@1.x.x: 394 | version "1.0.0" 395 | resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" 396 | integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= 397 | 398 | passport-twitter@^1.0.4: 399 | version "1.0.4" 400 | resolved "https://registry.yarnpkg.com/passport-twitter/-/passport-twitter-1.0.4.tgz#01a799e1f760bf2de49f2ba5fba32282f18932d7" 401 | integrity sha1-AaeZ4fdgvy3knyul+6MigvGJMtc= 402 | dependencies: 403 | passport-oauth1 "1.x.x" 404 | xtraverse "0.1.x" 405 | 406 | passport@^0.4.0: 407 | version "0.4.0" 408 | resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811" 409 | integrity sha1-xQlWkTR71a07XhgCOMORTRbwWBE= 410 | dependencies: 411 | passport-strategy "1.x.x" 412 | pause "0.0.1" 413 | 414 | path-to-regexp@0.1.7: 415 | version "0.1.7" 416 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 417 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 418 | 419 | pause@0.0.1: 420 | version "0.0.1" 421 | resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" 422 | integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= 423 | 424 | proxy-addr@~2.0.4: 425 | version "2.0.4" 426 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" 427 | integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== 428 | dependencies: 429 | forwarded "~0.1.2" 430 | ipaddr.js "1.8.0" 431 | 432 | qs@6.5.2: 433 | version "6.5.2" 434 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 435 | integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== 436 | 437 | random-bytes@~1.0.0: 438 | version "1.0.0" 439 | resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" 440 | integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= 441 | 442 | range-parser@~1.2.0: 443 | version "1.2.0" 444 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 445 | integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= 446 | 447 | raw-body@2.3.3: 448 | version "2.3.3" 449 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" 450 | integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== 451 | dependencies: 452 | bytes "3.0.0" 453 | http-errors "1.6.3" 454 | iconv-lite "0.4.23" 455 | unpipe "1.0.0" 456 | 457 | regexp-clone@1.0.0, regexp-clone@^1.0.0: 458 | version "1.0.0" 459 | resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" 460 | integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== 461 | 462 | require_optional@^1.0.1: 463 | version "1.0.1" 464 | resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" 465 | integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== 466 | dependencies: 467 | resolve-from "^2.0.0" 468 | semver "^5.1.0" 469 | 470 | resolve-from@^2.0.0: 471 | version "2.0.0" 472 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" 473 | integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= 474 | 475 | safe-buffer@5.1.1: 476 | version "5.1.1" 477 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 478 | integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== 479 | 480 | safe-buffer@5.1.2, safe-buffer@^5.1.2: 481 | version "5.1.2" 482 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 483 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 484 | 485 | "safer-buffer@>= 2.1.2 < 3": 486 | version "2.1.2" 487 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 488 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 489 | 490 | semver@^5.1.0: 491 | version "5.6.0" 492 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" 493 | integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== 494 | 495 | send@0.16.2: 496 | version "0.16.2" 497 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" 498 | integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== 499 | dependencies: 500 | debug "2.6.9" 501 | depd "~1.1.2" 502 | destroy "~1.0.4" 503 | encodeurl "~1.0.2" 504 | escape-html "~1.0.3" 505 | etag "~1.8.1" 506 | fresh "0.5.2" 507 | http-errors "~1.6.2" 508 | mime "1.4.1" 509 | ms "2.0.0" 510 | on-finished "~2.3.0" 511 | range-parser "~1.2.0" 512 | statuses "~1.4.0" 513 | 514 | serve-static@1.13.2: 515 | version "1.13.2" 516 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" 517 | integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== 518 | dependencies: 519 | encodeurl "~1.0.2" 520 | escape-html "~1.0.3" 521 | parseurl "~1.3.2" 522 | send "0.16.2" 523 | 524 | setprototypeof@1.1.0: 525 | version "1.1.0" 526 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 527 | integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== 528 | 529 | sift@7.0.1: 530 | version "7.0.1" 531 | resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" 532 | integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== 533 | 534 | sliced@1.0.1: 535 | version "1.0.1" 536 | resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" 537 | integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= 538 | 539 | "statuses@>= 1.4.0 < 2": 540 | version "1.5.0" 541 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 542 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 543 | 544 | statuses@~1.4.0: 545 | version "1.4.0" 546 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" 547 | integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== 548 | 549 | type-is@~1.6.16: 550 | version "1.6.16" 551 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" 552 | integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== 553 | dependencies: 554 | media-typer "0.3.0" 555 | mime-types "~2.1.18" 556 | 557 | uid-safe@~2.1.5: 558 | version "2.1.5" 559 | resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" 560 | integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA== 561 | dependencies: 562 | random-bytes "~1.0.0" 563 | 564 | unpipe@1.0.0, unpipe@~1.0.0: 565 | version "1.0.0" 566 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 567 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 568 | 569 | utils-merge@1.0.1, utils-merge@1.x.x: 570 | version "1.0.1" 571 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 572 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 573 | 574 | vary@^1, vary@~1.1.2: 575 | version "1.1.2" 576 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 577 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 578 | 579 | xmldom@0.1.x: 580 | version "0.1.27" 581 | resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" 582 | integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= 583 | 584 | xtraverse@0.1.x: 585 | version "0.1.0" 586 | resolved "https://registry.yarnpkg.com/xtraverse/-/xtraverse-0.1.0.tgz#b741bad018ef78d8a9d2e83ade007b3f7959c732" 587 | integrity sha1-t0G60BjveNip0ug63gB7P3lZxzI= 588 | dependencies: 589 | xmldom "0.1.x" 590 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | --------------------------------------------------------------------------------