├── .gitignore
├── .vscode
└── settings.json
├── client
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
├── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── actions
│ │ ├── authActions.js
│ │ └── types.js
│ ├── components
│ │ ├── auth
│ │ │ ├── Login.js
│ │ │ └── Register.js
│ │ ├── guards
│ │ │ ├── IsAdmin.js
│ │ │ ├── IsAuth.js
│ │ │ ├── IsModerator.js
│ │ │ └── NotAuth.js
│ │ ├── home
│ │ │ └── Home.js
│ │ ├── layouts
│ │ │ ├── Banner.js
│ │ │ ├── Navbar.js
│ │ │ └── Sidebar.js
│ │ ├── notfound
│ │ │ └── NotFound.js
│ │ └── user
│ │ │ ├── admin
│ │ │ └── Admin.js
│ │ │ ├── dashboard
│ │ │ └── Dashboard.js
│ │ │ └── moderator
│ │ │ └── Moderator.js
│ ├── index.js
│ ├── reducers
│ │ ├── authReducers.js
│ │ ├── errorReducers.js
│ │ └── index.js
│ ├── registerServiceWorker.js
│ ├── store.js
│ └── utils
│ │ └── setAuthToken.js
└── yarn.lock
├── config
├── dbSecretKeys.js
├── dbSecretKeysProd.js
└── passport.js
├── guards
├── isAdmin.js
└── isModerator.js
├── models
└── User.js
├── package-lock.json
├── package.json
├── routes
└── api
│ ├── auth.js
│ └── users.js
├── server.js
└── utils
└── isEmpty.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /config/dbSecretKeysDev.js
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | }
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.18.0",
7 | "classnames": "^2.2.6",
8 | "jwt-decode": "^2.2.0",
9 | "react": "^16.4.2",
10 | "react-dom": "^16.4.2",
11 | "react-redux": "^5.0.7",
12 | "react-router-dom": "^4.3.1",
13 | "react-scripts": "1.1.4",
14 | "redux": "^4.0.0",
15 | "redux-thunk": "^2.3.0"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test --env=jsdom",
21 | "eject": "react-scripts eject"
22 | },
23 | "proxy": "http://localhost:5000"
24 | }
25 |
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nbagonoc/mern-multiple-user/9c3e5e973382247758c741f27ba665e226a05e53/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 | React App
14 |
15 |
16 |
17 |
20 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/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": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nbagonoc/mern-multiple-user/9c3e5e973382247758c741f27ba665e226a05e53/client/src/App.css
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
3 | import jwt_decode from "jwt-decode";
4 | import setAuthToken from "./utils/setAuthToken";
5 | import { setCurrentUser, logoutUser } from "./actions/authActions";
6 | import { Provider } from "react-redux";
7 | import store from "./store";
8 |
9 | // COMPONENTS
10 | // layout
11 | import Navbar from "./components/layouts/Navbar";
12 | // pages
13 | import Home from "./components/home/Home";
14 | import Register from "./components/auth/Register";
15 | import Login from "./components/auth/Login";
16 | import Dashboard from "./components/user/dashboard/Dashboard";
17 | import Moderator from "./components/user/moderator/Moderator";
18 | import Admin from "./components/user/admin/Admin";
19 | import NotFound from "./components/notfound/NotFound";
20 | // guards
21 | import NotAuth from "./components/guards/NotAuth";
22 | import IsAuth from "./components/guards/IsAuth";
23 | import IsModerator from "./components/guards/IsModerator";
24 | import IsAdmin from "./components/guards/IsAdmin";
25 |
26 | // ASSETS
27 | import "./App.css";
28 |
29 | // TOKEN CHECKER
30 | // Checks the local storage if there's a token, and if it still valid
31 | if (localStorage.jwtToken) {
32 | // set auth token header auth
33 | setAuthToken(localStorage.jwtToken);
34 | // decode token and get suer info and expiration
35 | const decoded = jwt_decode(localStorage.jwtToken);
36 | // set user and isAuthenticated
37 | store.dispatch(setCurrentUser(decoded));
38 |
39 | // check for epired token
40 | const currentTime = Date.now() / 1000;
41 | if (decoded.exp < currentTime) {
42 | // logout user
43 | store.dispatch(logoutUser());
44 | }
45 | }
46 |
47 | class App extends Component {
48 | render() {
49 | return (
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | );
67 | }
68 | }
69 |
70 | export default App;
71 |
--------------------------------------------------------------------------------
/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/actions/authActions.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import setAuthToken from "../utils/setAuthToken";
3 | import jwt_decode from "jwt-decode";
4 |
5 | import {
6 | SET_CURRENT_USER,
7 | CLEAR_CURRENT_USER,
8 | GET_ERRORS,
9 | CLEAR_ERRORS
10 | } from "./types";
11 |
12 | // register user
13 | export const registerUser = (userData, history) => dispatch => {
14 | axios
15 | .post("/api/auth/register", userData)
16 | .then(res => {
17 | // redirect user to login page
18 | history.push("/login");
19 | // clear errors
20 | dispatch({
21 | type: CLEAR_ERRORS,
22 | payload: {}
23 | });
24 | })
25 | .catch(err =>
26 | dispatch({
27 | type: GET_ERRORS,
28 | payload: err.response.data
29 | })
30 | );
31 | };
32 |
33 | // login user
34 | export const loginUser = (userData, history) => dispatch => {
35 | axios
36 | .post("/api/auth/login", userData)
37 | .then(res => {
38 | // save to localStorage
39 | const { token } = res.data;
40 | // set token to localStorage
41 | localStorage.setItem("jwtToken", token);
42 | // set token to auth header
43 | setAuthToken(token);
44 | // decode token to get user data
45 | const decoded = jwt_decode(token);
46 | // set current user
47 | dispatch(setCurrentUser(decoded));
48 | // redirect user
49 | history.push("/dashboard");
50 | // clear errors
51 | dispatch({
52 | type: CLEAR_ERRORS,
53 | payload: {}
54 | });
55 | })
56 | .catch(err =>
57 | dispatch({
58 | type: GET_ERRORS,
59 | payload: err.response.data
60 | })
61 | );
62 | };
63 |
64 | // set token of logged in user
65 | export const setCurrentUser = decoded => {
66 | return {
67 | type: SET_CURRENT_USER,
68 | payload: decoded
69 | };
70 | };
71 |
72 | // log user out
73 | export const logoutUser = () => dispatch => {
74 | // remove token from localStorage
75 | localStorage.removeItem("jwtToken");
76 | // Clear the current user
77 | dispatch({
78 | type: CLEAR_CURRENT_USER,
79 | payload: {}
80 | });
81 | };
82 |
--------------------------------------------------------------------------------
/client/src/actions/types.js:
--------------------------------------------------------------------------------
1 | export const SET_CURRENT_USER = "SET_CURRENT_USER";
2 | export const CLEAR_CURRENT_USER = "CLEAR_CURRENT_USER";
3 | export const GET_ERRORS = "GET_ERRORS";
4 | export const CLEAR_ERRORS = "CLEAR_ERRORS";
5 |
--------------------------------------------------------------------------------
/client/src/components/auth/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 | import { Link } from "react-router-dom";
4 | import { connect } from "react-redux";
5 | import { loginUser } from "../../actions/authActions";
6 | import classnames from "classnames";
7 |
8 | class Login extends Component {
9 | state = {
10 | email: "",
11 | password: "",
12 | errors: {}
13 | };
14 |
15 | onChange = e => {
16 | this.setState({ [e.target.name]: e.target.value });
17 | };
18 |
19 | onSubmitHandler = e => {
20 | e.preventDefault();
21 |
22 | const userData = {
23 | email: this.state.email,
24 | password: this.state.password
25 | };
26 |
27 | this.props.loginUser(userData, this.props.history);
28 | };
29 |
30 | componentWillReceiveProps(nextProps) {
31 | if (nextProps.errors) {
32 | this.setState({ errors: nextProps.errors });
33 | }
34 | }
35 |
36 | render() {
37 | const { email, password, errors } = this.state;
38 |
39 | return (
40 |
95 | );
96 | }
97 | }
98 |
99 | Login.propTypes = {
100 | loginUser: PropTypes.func.isRequired,
101 | auth: PropTypes.object.isRequired,
102 | errors: PropTypes.object.isRequired
103 | };
104 |
105 | const mapStateToProps = state => ({
106 | auth: state.auth,
107 | errors: state.errors
108 | });
109 |
110 | export default connect(
111 | mapStateToProps,
112 | { loginUser }
113 | )(Login);
114 |
--------------------------------------------------------------------------------
/client/src/components/auth/Register.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 | import { Link } from "react-router-dom";
4 | import { connect } from "react-redux";
5 | import { registerUser } from "../../actions/authActions";
6 | import classnames from "classnames";
7 |
8 | class Register extends Component {
9 | state = {
10 | name: "",
11 | email: "",
12 | password: "",
13 | password2: "",
14 | errors: {}
15 | };
16 |
17 | onChange = e => {
18 | this.setState({ [e.target.name]: e.target.value });
19 | };
20 |
21 | onSubmitHandler = e => {
22 | e.preventDefault();
23 |
24 | const newUser = {
25 | name: this.state.name,
26 | email: this.state.email,
27 | password: this.state.password,
28 | password2: this.state.password2
29 | };
30 |
31 | this.props.registerUser(newUser, this.props.history);
32 | };
33 |
34 | componentWillReceiveProps(nextProps) {
35 | if (nextProps.errors) {
36 | this.setState({ errors: nextProps.errors });
37 | }
38 | }
39 |
40 | render() {
41 | const { name, email, password, password2, errors } = this.state;
42 |
43 | return (
44 |
138 | );
139 | }
140 | }
141 |
142 | Register.propTypes = {
143 | registerUser: PropTypes.func.isRequired,
144 | auth: PropTypes.object.isRequired,
145 | errors: PropTypes.object.isRequired
146 | };
147 |
148 | const mapStateToProps = state => ({
149 | auth: state.auth,
150 | errors: state.errors
151 | });
152 |
153 | export default connect(
154 | mapStateToProps,
155 | { registerUser }
156 | )(Register);
157 |
--------------------------------------------------------------------------------
/client/src/components/guards/IsAdmin.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Route, Redirect } from "react-router-dom";
3 | import { connect } from "react-redux";
4 | import PropTypes from "prop-types";
5 |
6 | const IsAdmin = ({ component: Component, auth, ...rest }) => (
7 |
10 | auth.isAuthenticated === true ? (
11 | auth.user.role === "admin" ? (
12 |
13 | ) : (
14 |
15 | )
16 | ) : (
17 |
18 | )
19 | }
20 | />
21 | );
22 |
23 | IsAdmin.propTypes = {
24 | auth: PropTypes.object.isRequired
25 | };
26 |
27 | const mapStateToProps = state => ({
28 | auth: state.auth
29 | });
30 |
31 | export default connect(mapStateToProps)(IsAdmin);
32 |
--------------------------------------------------------------------------------
/client/src/components/guards/IsAuth.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Route, Redirect } from "react-router-dom";
3 | import { connect } from "react-redux";
4 | import PropTypes from "prop-types";
5 |
6 | const IsAuth = ({ component: Component, auth, ...rest }) => (
7 |
10 | auth.isAuthenticated === true ? (
11 |
12 | ) : (
13 |
14 | )
15 | }
16 | />
17 | );
18 |
19 | IsAuth.propTypes = {
20 | auth: PropTypes.object.isRequired
21 | };
22 |
23 | const mapStateToProps = state => ({
24 | auth: state.auth
25 | });
26 |
27 | export default connect(mapStateToProps)(IsAuth);
28 |
--------------------------------------------------------------------------------
/client/src/components/guards/IsModerator.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Route, Redirect } from "react-router-dom";
3 | import { connect } from "react-redux";
4 | import PropTypes from "prop-types";
5 |
6 | const IsModerator = ({ component: Component, auth, ...rest }) => (
7 |
10 | auth.isAuthenticated === true ? (
11 | auth.user.role === "moderator" || auth.user.role === "admin" ? (
12 |
13 | ) : (
14 |
15 | )
16 | ) : (
17 |
18 | )
19 | }
20 | />
21 | );
22 |
23 | IsModerator.propTypes = {
24 | auth: PropTypes.object.isRequired
25 | };
26 |
27 | const mapStateToProps = state => ({
28 | auth: state.auth
29 | });
30 |
31 | export default connect(mapStateToProps)(IsModerator);
32 |
--------------------------------------------------------------------------------
/client/src/components/guards/NotAuth.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Route, Redirect } from "react-router-dom";
3 | import { connect } from "react-redux";
4 | import PropTypes from "prop-types";
5 |
6 | const IsAuth = ({ component: Component, auth, ...rest }) => (
7 |
10 | auth.isAuthenticated === false ? (
11 |
12 | ) : (
13 |
14 | )
15 | }
16 | />
17 | );
18 |
19 | IsAuth.propTypes = {
20 | auth: PropTypes.object.isRequired
21 | };
22 |
23 | const mapStateToProps = state => ({
24 | auth: state.auth
25 | });
26 |
27 | export default connect(mapStateToProps)(IsAuth);
28 |
--------------------------------------------------------------------------------
/client/src/components/home/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | // COMPONENTS
4 | import Banner from "../layouts/Banner";
5 |
6 | const Home = () => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 |
14 | export default Home;
15 |
--------------------------------------------------------------------------------
/client/src/components/layouts/Banner.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Banner = () => {
4 | return (
5 |
6 |
7 | MERN Stack Boilerplate
8 |
9 |
10 | A MERN Stack boilerplate with multiple auth user roles using JWT
11 |
12 |
13 | );
14 | };
15 |
16 | export default Banner;
17 |
--------------------------------------------------------------------------------
/client/src/components/layouts/Navbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Link } from "react-router-dom";
3 | import PropTypes from "prop-types";
4 | import { connect } from "react-redux";
5 | import { logoutUser } from "../../actions/authActions";
6 |
7 | class Navbar extends Component {
8 | onLogout(e) {
9 | e.preventDefault();
10 | this.props.logoutUser();
11 | }
12 |
13 | render() {
14 | const { isAuthenticated, user } = this.props.auth;
15 |
16 | return (
17 |
18 |
84 |
85 | );
86 | }
87 | }
88 |
89 | Navbar.propTypes = {
90 | logoutUser: PropTypes.func.isRequired,
91 | auth: PropTypes.object.isRequired
92 | };
93 |
94 | const mapStateToProps = state => ({
95 | auth: state.auth
96 | });
97 |
98 | export default connect(
99 | mapStateToProps,
100 | { logoutUser }
101 | )(Navbar);
102 |
--------------------------------------------------------------------------------
/client/src/components/layouts/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { Link } from "react-router-dom";
3 | import PropTypes from "prop-types";
4 | import { connect } from "react-redux";
5 |
6 | class Sidebar extends Component {
7 | render() {
8 | const { user } = this.props.auth;
9 |
10 | return (
11 |
12 | {/* moderator lvl */}
13 | {user.role === "moderator" || user.role === "admin" ? (
14 |
15 |
19 | Dashboard
20 |
21 |
25 | Moderator Page
26 |
27 | {/* Admin lvl only*/}
28 | {user.role === "admin" ? (
29 |
33 | Admin Page
34 |
35 | ) : null}
36 |
37 | ) : (
38 |
39 | {/* user lvl */}
40 |
44 | Dashboard
45 |
46 |
47 | )}
48 |
49 | );
50 | }
51 | }
52 |
53 | Sidebar.proptypes = {
54 | auth: PropTypes.object.isRequired
55 | };
56 |
57 | const mapStateToProps = state => ({
58 | auth: state.auth
59 | });
60 |
61 | export default connect(mapStateToProps)(Sidebar);
62 |
--------------------------------------------------------------------------------
/client/src/components/notfound/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 |
4 | const NotFound = () => {
5 | return (
6 |
7 |
Error 404
8 |
9 | The page you're looking for does not exist
10 |
11 |
12 | Back to Home
13 |
14 |
15 | );
16 | };
17 |
18 | export default NotFound;
19 |
--------------------------------------------------------------------------------
/client/src/components/user/admin/Admin.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Sidebar from "../../layouts/Sidebar";
3 |
4 | class Admin extends Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Welcome to the admin page
15 |
16 | Only the Adminstrator can access this page
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | export default Admin;
27 |
--------------------------------------------------------------------------------
/client/src/components/user/dashboard/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Sidebar from "../../layouts/Sidebar";
3 |
4 | class Dashboard extends Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Welcome to the dashboard
15 |
16 | Every user that is authenticated can access the dashboard
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | export default Dashboard;
27 |
--------------------------------------------------------------------------------
/client/src/components/user/moderator/Moderator.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Sidebar from "../../layouts/Sidebar";
3 |
4 | class Moderator extends Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
Welcome to the moderator page
15 |
16 | The administrator and moderator can access this page
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
26 | export default Moderator;
27 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import App from "./App";
4 | import registerServiceWorker from "./registerServiceWorker";
5 |
6 | ReactDOM.render(, document.getElementById("root"));
7 | registerServiceWorker();
8 |
--------------------------------------------------------------------------------
/client/src/reducers/authReducers.js:
--------------------------------------------------------------------------------
1 | import { SET_CURRENT_USER, CLEAR_CURRENT_USER } from "../actions/types";
2 |
3 | const initialState = {
4 | isAuthenticated: false,
5 | user: {}
6 | };
7 |
8 | export default function(state = initialState, action) {
9 | switch (action.type) {
10 | case SET_CURRENT_USER:
11 | return {
12 | ...state,
13 | isAuthenticated: true,
14 | user: action.payload
15 | };
16 | case CLEAR_CURRENT_USER:
17 | return {
18 | ...state,
19 | isAuthenticated: false,
20 | user: action.payload
21 | };
22 | default:
23 | return state;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/reducers/errorReducers.js:
--------------------------------------------------------------------------------
1 | import { GET_ERRORS, CLEAR_ERRORS } from "../actions/types";
2 |
3 | const initialState = {};
4 |
5 | export default function(state = initialState, action) {
6 | switch (action.type) {
7 | case GET_ERRORS:
8 | return action.payload;
9 | case CLEAR_ERRORS:
10 | return {};
11 | default:
12 | return state;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux";
2 | import authReducers from "./authReducers";
3 | import errorReducers from "./errorReducers";
4 |
5 | export default combineReducers({
6 | auth: authReducers,
7 | errors: errorReducers
8 | });
9 |
--------------------------------------------------------------------------------
/client/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/client/src/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose } from "redux";
2 | import thunk from "redux-thunk";
3 | import rootReducer from "./reducers";
4 |
5 | const initialState = {};
6 |
7 | const middleware = [thunk];
8 |
9 | const store = createStore(
10 | rootReducer,
11 | initialState,
12 | compose(
13 | applyMiddleware(...middleware),
14 | window.navigator.userAgent.includes("Chrome")
15 | ? window.__REDUX_DEVTOOLS_EXTENSION__ &&
16 | window.__REDUX_DEVTOOLS_EXTENSION__()
17 | : compose
18 | )
19 | );
20 |
21 | export default store;
22 |
--------------------------------------------------------------------------------
/client/src/utils/setAuthToken.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const setAuthToken = token => {
4 | if (token) {
5 | // apply to every request
6 | axios.defaults.headers.common["Authorization"] = token;
7 | } else {
8 | // delete auth header
9 | delete axios.defaults.headers.common["Authorization"];
10 | }
11 | };
12 |
13 | export default setAuthToken;
14 |
--------------------------------------------------------------------------------
/config/dbSecretKeys.js:
--------------------------------------------------------------------------------
1 | if (process.env.NODE_ENV === "production") {
2 | module.exports = require("./dbSecretKeysProd");
3 | } else {
4 | module.exports = require("./dbSecretKeysDev");
5 | }
6 |
--------------------------------------------------------------------------------
/config/dbSecretKeysProd.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mongoURI: process.env.MONGO_URI,
3 | secretOrKey: process.env.SECRET_OR_KEY
4 | };
5 |
--------------------------------------------------------------------------------
/config/passport.js:
--------------------------------------------------------------------------------
1 | const JwtStrategy = require("passport-jwt").Strategy;
2 | const ExtractJwt = require("passport-jwt").ExtractJwt;
3 | const mongoose = require("mongoose");
4 | const User = mongoose.model("users");
5 | const keys = require("./dbSecretKeys");
6 |
7 | let opts = {};
8 | // opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
9 | opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("jwt");
10 | opts.secretOrKey = keys.secretOrKey;
11 |
12 | module.exports = passport => {
13 | passport.use(
14 | new JwtStrategy(opts, (jwt_payload, done) => {
15 | User.findById(jwt_payload.id)
16 | .then(user => {
17 | if (user) {
18 | return done(null, user);
19 | }
20 | return done(null, false);
21 | })
22 | .catch(err => console.log(err));
23 | })
24 | );
25 | };
26 |
--------------------------------------------------------------------------------
/guards/isAdmin.js:
--------------------------------------------------------------------------------
1 | module.exports = function(req, res, next) {
2 | if (req.user.role != "admin") return res.status(403).send("Access Denied");
3 | next();
4 | };
5 |
--------------------------------------------------------------------------------
/guards/isModerator.js:
--------------------------------------------------------------------------------
1 | module.exports = function(req, res, next) {
2 | if (!(req.user.role == "moderator" || req.user.role == "admin"))
3 | return res.status(403).send("Access Denied");
4 | next();
5 | };
6 |
--------------------------------------------------------------------------------
/models/User.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | const { Schema } = mongoose;
3 |
4 | // Create Schema
5 | const userSchema = new Schema({
6 | name: {
7 | type: String
8 | },
9 | email: {
10 | type: String,
11 | required: true
12 | },
13 | role: {
14 | type: String,
15 | default: "subscriber"
16 | // roles available to this proj: admin, moderator, subscriber
17 | },
18 | password: {
19 | type: String
20 | }
21 | });
22 |
23 | // module.exports = User = mongoose.model("users", UserSchema);
24 | mongoose.model("users", userSchema);
25 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mern",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "accepts": {
8 | "version": "1.3.5",
9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
11 | "requires": {
12 | "mime-types": "~2.1.18",
13 | "negotiator": "0.6.1"
14 | }
15 | },
16 | "acorn": {
17 | "version": "5.7.1",
18 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz",
19 | "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ=="
20 | },
21 | "acorn-jsx": {
22 | "version": "3.0.1",
23 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
24 | "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
25 | "requires": {
26 | "acorn": "^3.0.4"
27 | },
28 | "dependencies": {
29 | "acorn": {
30 | "version": "3.3.0",
31 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
32 | "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo="
33 | }
34 | }
35 | },
36 | "ajv": {
37 | "version": "5.5.2",
38 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
39 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
40 | "requires": {
41 | "co": "^4.6.0",
42 | "fast-deep-equal": "^1.0.0",
43 | "fast-json-stable-stringify": "^2.0.0",
44 | "json-schema-traverse": "^0.3.0"
45 | }
46 | },
47 | "ajv-keywords": {
48 | "version": "3.2.0",
49 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz",
50 | "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo="
51 | },
52 | "ansi-escapes": {
53 | "version": "3.1.0",
54 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz",
55 | "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw=="
56 | },
57 | "ansi-regex": {
58 | "version": "2.1.1",
59 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
60 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
61 | },
62 | "ansi-styles": {
63 | "version": "2.2.1",
64 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
65 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
66 | },
67 | "argparse": {
68 | "version": "1.0.10",
69 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
70 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
71 | "requires": {
72 | "sprintf-js": "~1.0.2"
73 | }
74 | },
75 | "array-flatten": {
76 | "version": "1.1.1",
77 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
78 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
79 | },
80 | "array-union": {
81 | "version": "1.0.2",
82 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
83 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
84 | "requires": {
85 | "array-uniq": "^1.0.1"
86 | }
87 | },
88 | "array-uniq": {
89 | "version": "1.0.3",
90 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
91 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
92 | },
93 | "arrify": {
94 | "version": "1.0.1",
95 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
96 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
97 | },
98 | "async": {
99 | "version": "2.6.1",
100 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
101 | "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
102 | "requires": {
103 | "lodash": "^4.17.10"
104 | }
105 | },
106 | "babel-code-frame": {
107 | "version": "6.26.0",
108 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
109 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
110 | "requires": {
111 | "chalk": "^1.1.3",
112 | "esutils": "^2.0.2",
113 | "js-tokens": "^3.0.2"
114 | },
115 | "dependencies": {
116 | "chalk": {
117 | "version": "1.1.3",
118 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
119 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
120 | "requires": {
121 | "ansi-styles": "^2.2.1",
122 | "escape-string-regexp": "^1.0.2",
123 | "has-ansi": "^2.0.0",
124 | "strip-ansi": "^3.0.0",
125 | "supports-color": "^2.0.0"
126 | }
127 | },
128 | "strip-ansi": {
129 | "version": "3.0.1",
130 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
131 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
132 | "requires": {
133 | "ansi-regex": "^2.0.0"
134 | }
135 | }
136 | }
137 | },
138 | "balanced-match": {
139 | "version": "1.0.0",
140 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
141 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
142 | },
143 | "bcryptjs": {
144 | "version": "2.4.3",
145 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
146 | "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
147 | },
148 | "bluebird": {
149 | "version": "3.5.1",
150 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
151 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
152 | },
153 | "body-parser": {
154 | "version": "1.18.3",
155 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
156 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
157 | "requires": {
158 | "bytes": "3.0.0",
159 | "content-type": "~1.0.4",
160 | "debug": "2.6.9",
161 | "depd": "~1.1.2",
162 | "http-errors": "~1.6.3",
163 | "iconv-lite": "0.4.23",
164 | "on-finished": "~2.3.0",
165 | "qs": "6.5.2",
166 | "raw-body": "2.3.3",
167 | "type-is": "~1.6.16"
168 | }
169 | },
170 | "brace-expansion": {
171 | "version": "1.1.11",
172 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
173 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
174 | "requires": {
175 | "balanced-match": "^1.0.0",
176 | "concat-map": "0.0.1"
177 | }
178 | },
179 | "bson": {
180 | "version": "1.0.9",
181 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.9.tgz",
182 | "integrity": "sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg=="
183 | },
184 | "buffer-equal-constant-time": {
185 | "version": "1.0.1",
186 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
187 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
188 | },
189 | "buffer-from": {
190 | "version": "1.1.1",
191 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
192 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
193 | },
194 | "builtin-modules": {
195 | "version": "1.1.1",
196 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
197 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
198 | },
199 | "bytes": {
200 | "version": "3.0.0",
201 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
202 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
203 | },
204 | "caller-path": {
205 | "version": "0.1.0",
206 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
207 | "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
208 | "requires": {
209 | "callsites": "^0.2.0"
210 | }
211 | },
212 | "callsites": {
213 | "version": "0.2.0",
214 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
215 | "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo="
216 | },
217 | "chalk": {
218 | "version": "2.4.1",
219 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
220 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
221 | "requires": {
222 | "ansi-styles": "^3.2.1",
223 | "escape-string-regexp": "^1.0.5",
224 | "supports-color": "^5.3.0"
225 | },
226 | "dependencies": {
227 | "ansi-styles": {
228 | "version": "3.2.1",
229 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
230 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
231 | "requires": {
232 | "color-convert": "^1.9.0"
233 | }
234 | },
235 | "supports-color": {
236 | "version": "5.4.0",
237 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
238 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
239 | "requires": {
240 | "has-flag": "^3.0.0"
241 | }
242 | }
243 | }
244 | },
245 | "chardet": {
246 | "version": "0.4.2",
247 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
248 | "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
249 | },
250 | "circular-json": {
251 | "version": "0.3.3",
252 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
253 | "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
254 | },
255 | "cli-cursor": {
256 | "version": "2.1.0",
257 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
258 | "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
259 | "requires": {
260 | "restore-cursor": "^2.0.0"
261 | }
262 | },
263 | "cli-width": {
264 | "version": "2.2.0",
265 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
266 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
267 | },
268 | "co": {
269 | "version": "4.6.0",
270 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
271 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
272 | },
273 | "color-convert": {
274 | "version": "1.9.2",
275 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
276 | "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
277 | "requires": {
278 | "color-name": "1.1.1"
279 | }
280 | },
281 | "color-name": {
282 | "version": "1.1.1",
283 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
284 | "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok="
285 | },
286 | "commander": {
287 | "version": "2.6.0",
288 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz",
289 | "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0="
290 | },
291 | "concat-map": {
292 | "version": "0.0.1",
293 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
294 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
295 | },
296 | "concat-stream": {
297 | "version": "1.6.2",
298 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
299 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
300 | "requires": {
301 | "buffer-from": "^1.0.0",
302 | "inherits": "^2.0.3",
303 | "readable-stream": "^2.2.2",
304 | "typedarray": "^0.0.6"
305 | }
306 | },
307 | "concurrently": {
308 | "version": "3.6.1",
309 | "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.1.tgz",
310 | "integrity": "sha512-/+ugz+gwFSEfTGUxn0KHkY+19XPRTXR8+7oUK/HxgiN1n7FjeJmkrbSiXAJfyQ0zORgJYPaenmymwon51YXH9Q==",
311 | "requires": {
312 | "chalk": "^2.4.1",
313 | "commander": "2.6.0",
314 | "date-fns": "^1.23.0",
315 | "lodash": "^4.5.1",
316 | "read-pkg": "^3.0.0",
317 | "rx": "2.3.24",
318 | "spawn-command": "^0.0.2-1",
319 | "supports-color": "^3.2.3",
320 | "tree-kill": "^1.1.0"
321 | },
322 | "dependencies": {
323 | "has-flag": {
324 | "version": "1.0.0",
325 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
326 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
327 | },
328 | "supports-color": {
329 | "version": "3.2.3",
330 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
331 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
332 | "requires": {
333 | "has-flag": "^1.0.0"
334 | }
335 | }
336 | }
337 | },
338 | "content-disposition": {
339 | "version": "0.5.2",
340 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
341 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
342 | },
343 | "content-type": {
344 | "version": "1.0.4",
345 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
346 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
347 | },
348 | "cookie": {
349 | "version": "0.3.1",
350 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
351 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
352 | },
353 | "cookie-signature": {
354 | "version": "1.0.6",
355 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
356 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
357 | },
358 | "core-util-is": {
359 | "version": "1.0.2",
360 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
361 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
362 | },
363 | "cors": {
364 | "version": "2.8.4",
365 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz",
366 | "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=",
367 | "requires": {
368 | "object-assign": "^4",
369 | "vary": "^1"
370 | }
371 | },
372 | "cross-spawn": {
373 | "version": "5.1.0",
374 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
375 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
376 | "requires": {
377 | "lru-cache": "^4.0.1",
378 | "shebang-command": "^1.2.0",
379 | "which": "^1.2.9"
380 | }
381 | },
382 | "date-fns": {
383 | "version": "1.29.0",
384 | "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz",
385 | "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw=="
386 | },
387 | "debug": {
388 | "version": "2.6.9",
389 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
390 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
391 | "requires": {
392 | "ms": "2.0.0"
393 | }
394 | },
395 | "deep-is": {
396 | "version": "0.1.3",
397 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
398 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
399 | },
400 | "del": {
401 | "version": "2.2.2",
402 | "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
403 | "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
404 | "requires": {
405 | "globby": "^5.0.0",
406 | "is-path-cwd": "^1.0.0",
407 | "is-path-in-cwd": "^1.0.0",
408 | "object-assign": "^4.0.1",
409 | "pify": "^2.0.0",
410 | "pinkie-promise": "^2.0.0",
411 | "rimraf": "^2.2.8"
412 | }
413 | },
414 | "depd": {
415 | "version": "1.1.2",
416 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
417 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
418 | },
419 | "destroy": {
420 | "version": "1.0.4",
421 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
422 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
423 | },
424 | "doctrine": {
425 | "version": "2.1.0",
426 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
427 | "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
428 | "requires": {
429 | "esutils": "^2.0.2"
430 | }
431 | },
432 | "ecdsa-sig-formatter": {
433 | "version": "1.0.10",
434 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz",
435 | "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=",
436 | "requires": {
437 | "safe-buffer": "^5.0.1"
438 | }
439 | },
440 | "ee-first": {
441 | "version": "1.1.1",
442 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
443 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
444 | },
445 | "encodeurl": {
446 | "version": "1.0.2",
447 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
448 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
449 | },
450 | "error-ex": {
451 | "version": "1.3.2",
452 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
453 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
454 | "requires": {
455 | "is-arrayish": "^0.2.1"
456 | }
457 | },
458 | "escape-html": {
459 | "version": "1.0.3",
460 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
461 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
462 | },
463 | "escape-string-regexp": {
464 | "version": "1.0.5",
465 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
466 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
467 | },
468 | "eslint": {
469 | "version": "4.14.0",
470 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.14.0.tgz",
471 | "integrity": "sha512-Ul6CSGRjKscEyg0X/EeNs7o2XdnbTEOD1OM8cTjmx85RPcBJQrEhZLevhuJZNAE/vS2iVl5Uhgiqf3h5uLMCJQ==",
472 | "requires": {
473 | "ajv": "^5.3.0",
474 | "babel-code-frame": "^6.22.0",
475 | "chalk": "^2.1.0",
476 | "concat-stream": "^1.6.0",
477 | "cross-spawn": "^5.1.0",
478 | "debug": "^3.1.0",
479 | "doctrine": "^2.0.2",
480 | "eslint-scope": "^3.7.1",
481 | "eslint-visitor-keys": "^1.0.0",
482 | "espree": "^3.5.2",
483 | "esquery": "^1.0.0",
484 | "esutils": "^2.0.2",
485 | "file-entry-cache": "^2.0.0",
486 | "functional-red-black-tree": "^1.0.1",
487 | "glob": "^7.1.2",
488 | "globals": "^11.0.1",
489 | "ignore": "^3.3.3",
490 | "imurmurhash": "^0.1.4",
491 | "inquirer": "^3.0.6",
492 | "is-resolvable": "^1.0.0",
493 | "js-yaml": "^3.9.1",
494 | "json-stable-stringify-without-jsonify": "^1.0.1",
495 | "levn": "^0.3.0",
496 | "lodash": "^4.17.4",
497 | "minimatch": "^3.0.2",
498 | "mkdirp": "^0.5.1",
499 | "natural-compare": "^1.4.0",
500 | "optionator": "^0.8.2",
501 | "path-is-inside": "^1.0.2",
502 | "pluralize": "^7.0.0",
503 | "progress": "^2.0.0",
504 | "require-uncached": "^1.0.3",
505 | "semver": "^5.3.0",
506 | "strip-ansi": "^4.0.0",
507 | "strip-json-comments": "~2.0.1",
508 | "table": "^4.0.1",
509 | "text-table": "~0.2.0"
510 | },
511 | "dependencies": {
512 | "debug": {
513 | "version": "3.1.0",
514 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
515 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
516 | "requires": {
517 | "ms": "2.0.0"
518 | }
519 | }
520 | }
521 | },
522 | "eslint-scope": {
523 | "version": "3.7.3",
524 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz",
525 | "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==",
526 | "requires": {
527 | "esrecurse": "^4.1.0",
528 | "estraverse": "^4.1.1"
529 | }
530 | },
531 | "eslint-visitor-keys": {
532 | "version": "1.0.0",
533 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
534 | "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ=="
535 | },
536 | "espree": {
537 | "version": "3.5.4",
538 | "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
539 | "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
540 | "requires": {
541 | "acorn": "^5.5.0",
542 | "acorn-jsx": "^3.0.0"
543 | }
544 | },
545 | "esprima": {
546 | "version": "4.0.1",
547 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
548 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
549 | },
550 | "esquery": {
551 | "version": "1.0.1",
552 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
553 | "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
554 | "requires": {
555 | "estraverse": "^4.0.0"
556 | }
557 | },
558 | "esrecurse": {
559 | "version": "4.2.1",
560 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
561 | "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
562 | "requires": {
563 | "estraverse": "^4.1.0"
564 | }
565 | },
566 | "estraverse": {
567 | "version": "4.2.0",
568 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
569 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
570 | },
571 | "esutils": {
572 | "version": "2.0.2",
573 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
574 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
575 | },
576 | "etag": {
577 | "version": "1.8.1",
578 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
579 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
580 | },
581 | "express": {
582 | "version": "4.16.3",
583 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
584 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
585 | "requires": {
586 | "accepts": "~1.3.5",
587 | "array-flatten": "1.1.1",
588 | "body-parser": "1.18.2",
589 | "content-disposition": "0.5.2",
590 | "content-type": "~1.0.4",
591 | "cookie": "0.3.1",
592 | "cookie-signature": "1.0.6",
593 | "debug": "2.6.9",
594 | "depd": "~1.1.2",
595 | "encodeurl": "~1.0.2",
596 | "escape-html": "~1.0.3",
597 | "etag": "~1.8.1",
598 | "finalhandler": "1.1.1",
599 | "fresh": "0.5.2",
600 | "merge-descriptors": "1.0.1",
601 | "methods": "~1.1.2",
602 | "on-finished": "~2.3.0",
603 | "parseurl": "~1.3.2",
604 | "path-to-regexp": "0.1.7",
605 | "proxy-addr": "~2.0.3",
606 | "qs": "6.5.1",
607 | "range-parser": "~1.2.0",
608 | "safe-buffer": "5.1.1",
609 | "send": "0.16.2",
610 | "serve-static": "1.13.2",
611 | "setprototypeof": "1.1.0",
612 | "statuses": "~1.4.0",
613 | "type-is": "~1.6.16",
614 | "utils-merge": "1.0.1",
615 | "vary": "~1.1.2"
616 | },
617 | "dependencies": {
618 | "body-parser": {
619 | "version": "1.18.2",
620 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
621 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
622 | "requires": {
623 | "bytes": "3.0.0",
624 | "content-type": "~1.0.4",
625 | "debug": "2.6.9",
626 | "depd": "~1.1.1",
627 | "http-errors": "~1.6.2",
628 | "iconv-lite": "0.4.19",
629 | "on-finished": "~2.3.0",
630 | "qs": "6.5.1",
631 | "raw-body": "2.3.2",
632 | "type-is": "~1.6.15"
633 | }
634 | },
635 | "iconv-lite": {
636 | "version": "0.4.19",
637 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
638 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
639 | },
640 | "qs": {
641 | "version": "6.5.1",
642 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
643 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
644 | },
645 | "raw-body": {
646 | "version": "2.3.2",
647 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
648 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
649 | "requires": {
650 | "bytes": "3.0.0",
651 | "http-errors": "1.6.2",
652 | "iconv-lite": "0.4.19",
653 | "unpipe": "1.0.0"
654 | },
655 | "dependencies": {
656 | "depd": {
657 | "version": "1.1.1",
658 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
659 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
660 | },
661 | "http-errors": {
662 | "version": "1.6.2",
663 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
664 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
665 | "requires": {
666 | "depd": "1.1.1",
667 | "inherits": "2.0.3",
668 | "setprototypeof": "1.0.3",
669 | "statuses": ">= 1.3.1 < 2"
670 | }
671 | },
672 | "setprototypeof": {
673 | "version": "1.0.3",
674 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
675 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
676 | }
677 | }
678 | },
679 | "statuses": {
680 | "version": "1.4.0",
681 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
682 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
683 | }
684 | }
685 | },
686 | "external-editor": {
687 | "version": "2.2.0",
688 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
689 | "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
690 | "requires": {
691 | "chardet": "^0.4.0",
692 | "iconv-lite": "^0.4.17",
693 | "tmp": "^0.0.33"
694 | }
695 | },
696 | "fast-deep-equal": {
697 | "version": "1.1.0",
698 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
699 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
700 | },
701 | "fast-json-stable-stringify": {
702 | "version": "2.0.0",
703 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
704 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
705 | },
706 | "fast-levenshtein": {
707 | "version": "2.0.6",
708 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
709 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
710 | },
711 | "figures": {
712 | "version": "2.0.0",
713 | "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
714 | "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
715 | "requires": {
716 | "escape-string-regexp": "^1.0.5"
717 | }
718 | },
719 | "file-entry-cache": {
720 | "version": "2.0.0",
721 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
722 | "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
723 | "requires": {
724 | "flat-cache": "^1.2.1",
725 | "object-assign": "^4.0.1"
726 | }
727 | },
728 | "finalhandler": {
729 | "version": "1.1.1",
730 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
731 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
732 | "requires": {
733 | "debug": "2.6.9",
734 | "encodeurl": "~1.0.2",
735 | "escape-html": "~1.0.3",
736 | "on-finished": "~2.3.0",
737 | "parseurl": "~1.3.2",
738 | "statuses": "~1.4.0",
739 | "unpipe": "~1.0.0"
740 | },
741 | "dependencies": {
742 | "statuses": {
743 | "version": "1.4.0",
744 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
745 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
746 | }
747 | }
748 | },
749 | "flat-cache": {
750 | "version": "1.3.0",
751 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
752 | "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
753 | "requires": {
754 | "circular-json": "^0.3.1",
755 | "del": "^2.0.2",
756 | "graceful-fs": "^4.1.2",
757 | "write": "^0.2.1"
758 | }
759 | },
760 | "forwarded": {
761 | "version": "0.1.2",
762 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
763 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
764 | },
765 | "fresh": {
766 | "version": "0.5.2",
767 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
768 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
769 | },
770 | "fs.realpath": {
771 | "version": "1.0.0",
772 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
773 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
774 | },
775 | "functional-red-black-tree": {
776 | "version": "1.0.1",
777 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
778 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
779 | },
780 | "glob": {
781 | "version": "7.1.2",
782 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
783 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
784 | "requires": {
785 | "fs.realpath": "^1.0.0",
786 | "inflight": "^1.0.4",
787 | "inherits": "2",
788 | "minimatch": "^3.0.4",
789 | "once": "^1.3.0",
790 | "path-is-absolute": "^1.0.0"
791 | }
792 | },
793 | "globals": {
794 | "version": "11.7.0",
795 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz",
796 | "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg=="
797 | },
798 | "globby": {
799 | "version": "5.0.0",
800 | "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
801 | "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
802 | "requires": {
803 | "array-union": "^1.0.1",
804 | "arrify": "^1.0.0",
805 | "glob": "^7.0.3",
806 | "object-assign": "^4.0.1",
807 | "pify": "^2.0.0",
808 | "pinkie-promise": "^2.0.0"
809 | }
810 | },
811 | "graceful-fs": {
812 | "version": "4.1.11",
813 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
814 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
815 | },
816 | "has-ansi": {
817 | "version": "2.0.0",
818 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
819 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
820 | "requires": {
821 | "ansi-regex": "^2.0.0"
822 | }
823 | },
824 | "has-flag": {
825 | "version": "3.0.0",
826 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
827 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
828 | },
829 | "hosted-git-info": {
830 | "version": "2.7.1",
831 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
832 | "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w=="
833 | },
834 | "http-errors": {
835 | "version": "1.6.3",
836 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
837 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
838 | "requires": {
839 | "depd": "~1.1.2",
840 | "inherits": "2.0.3",
841 | "setprototypeof": "1.1.0",
842 | "statuses": ">= 1.4.0 < 2"
843 | }
844 | },
845 | "iconv-lite": {
846 | "version": "0.4.23",
847 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
848 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
849 | "requires": {
850 | "safer-buffer": ">= 2.1.2 < 3"
851 | }
852 | },
853 | "ignore": {
854 | "version": "3.3.10",
855 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
856 | "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug=="
857 | },
858 | "imurmurhash": {
859 | "version": "0.1.4",
860 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
861 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
862 | },
863 | "inflight": {
864 | "version": "1.0.6",
865 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
866 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
867 | "requires": {
868 | "once": "^1.3.0",
869 | "wrappy": "1"
870 | }
871 | },
872 | "inherits": {
873 | "version": "2.0.3",
874 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
875 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
876 | },
877 | "inquirer": {
878 | "version": "3.3.0",
879 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
880 | "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
881 | "requires": {
882 | "ansi-escapes": "^3.0.0",
883 | "chalk": "^2.0.0",
884 | "cli-cursor": "^2.1.0",
885 | "cli-width": "^2.0.0",
886 | "external-editor": "^2.0.4",
887 | "figures": "^2.0.0",
888 | "lodash": "^4.3.0",
889 | "mute-stream": "0.0.7",
890 | "run-async": "^2.2.0",
891 | "rx-lite": "^4.0.8",
892 | "rx-lite-aggregates": "^4.0.8",
893 | "string-width": "^2.1.0",
894 | "strip-ansi": "^4.0.0",
895 | "through": "^2.3.6"
896 | }
897 | },
898 | "ipaddr.js": {
899 | "version": "1.8.0",
900 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
901 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4="
902 | },
903 | "is-arrayish": {
904 | "version": "0.2.1",
905 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
906 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
907 | },
908 | "is-builtin-module": {
909 | "version": "1.0.0",
910 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
911 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
912 | "requires": {
913 | "builtin-modules": "^1.0.0"
914 | }
915 | },
916 | "is-fullwidth-code-point": {
917 | "version": "2.0.0",
918 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
919 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
920 | },
921 | "is-path-cwd": {
922 | "version": "1.0.0",
923 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
924 | "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0="
925 | },
926 | "is-path-in-cwd": {
927 | "version": "1.0.1",
928 | "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
929 | "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
930 | "requires": {
931 | "is-path-inside": "^1.0.0"
932 | }
933 | },
934 | "is-path-inside": {
935 | "version": "1.0.1",
936 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
937 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
938 | "requires": {
939 | "path-is-inside": "^1.0.1"
940 | }
941 | },
942 | "is-promise": {
943 | "version": "2.1.0",
944 | "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
945 | "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
946 | },
947 | "is-resolvable": {
948 | "version": "1.1.0",
949 | "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
950 | "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
951 | },
952 | "isarray": {
953 | "version": "1.0.0",
954 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
955 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
956 | },
957 | "isexe": {
958 | "version": "2.0.0",
959 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
960 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
961 | },
962 | "js-tokens": {
963 | "version": "3.0.2",
964 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
965 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
966 | },
967 | "js-yaml": {
968 | "version": "3.12.0",
969 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
970 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
971 | "requires": {
972 | "argparse": "^1.0.7",
973 | "esprima": "^4.0.0"
974 | }
975 | },
976 | "json-parse-better-errors": {
977 | "version": "1.0.2",
978 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
979 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
980 | },
981 | "json-schema-traverse": {
982 | "version": "0.3.1",
983 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
984 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
985 | },
986 | "json-stable-stringify-without-jsonify": {
987 | "version": "1.0.1",
988 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
989 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
990 | },
991 | "jsonwebtoken": {
992 | "version": "8.3.0",
993 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz",
994 | "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==",
995 | "requires": {
996 | "jws": "^3.1.5",
997 | "lodash.includes": "^4.3.0",
998 | "lodash.isboolean": "^3.0.3",
999 | "lodash.isinteger": "^4.0.4",
1000 | "lodash.isnumber": "^3.0.3",
1001 | "lodash.isplainobject": "^4.0.6",
1002 | "lodash.isstring": "^4.0.1",
1003 | "lodash.once": "^4.0.0",
1004 | "ms": "^2.1.1"
1005 | },
1006 | "dependencies": {
1007 | "ms": {
1008 | "version": "2.1.1",
1009 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
1010 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
1011 | }
1012 | }
1013 | },
1014 | "jwa": {
1015 | "version": "1.1.6",
1016 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz",
1017 | "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==",
1018 | "requires": {
1019 | "buffer-equal-constant-time": "1.0.1",
1020 | "ecdsa-sig-formatter": "1.0.10",
1021 | "safe-buffer": "^5.0.1"
1022 | }
1023 | },
1024 | "jws": {
1025 | "version": "3.1.5",
1026 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz",
1027 | "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==",
1028 | "requires": {
1029 | "jwa": "^1.1.5",
1030 | "safe-buffer": "^5.0.1"
1031 | }
1032 | },
1033 | "kareem": {
1034 | "version": "2.2.1",
1035 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.2.1.tgz",
1036 | "integrity": "sha512-xpDFy8OxkFM+vK6pXy6JmH92ibeEFUuDWzas5M9L7MzVmHW3jzwAHxodCPV/BYkf4A31bVDLyonrMfp9RXb/oA=="
1037 | },
1038 | "levn": {
1039 | "version": "0.3.0",
1040 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
1041 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
1042 | "requires": {
1043 | "prelude-ls": "~1.1.2",
1044 | "type-check": "~0.3.2"
1045 | }
1046 | },
1047 | "load-json-file": {
1048 | "version": "4.0.0",
1049 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
1050 | "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
1051 | "requires": {
1052 | "graceful-fs": "^4.1.2",
1053 | "parse-json": "^4.0.0",
1054 | "pify": "^3.0.0",
1055 | "strip-bom": "^3.0.0"
1056 | },
1057 | "dependencies": {
1058 | "pify": {
1059 | "version": "3.0.0",
1060 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
1061 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
1062 | }
1063 | }
1064 | },
1065 | "lodash": {
1066 | "version": "4.17.10",
1067 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz",
1068 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg=="
1069 | },
1070 | "lodash.get": {
1071 | "version": "4.4.2",
1072 | "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
1073 | "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
1074 | },
1075 | "lodash.includes": {
1076 | "version": "4.3.0",
1077 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
1078 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
1079 | },
1080 | "lodash.isboolean": {
1081 | "version": "3.0.3",
1082 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
1083 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
1084 | },
1085 | "lodash.isinteger": {
1086 | "version": "4.0.4",
1087 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
1088 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
1089 | },
1090 | "lodash.isnumber": {
1091 | "version": "3.0.3",
1092 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
1093 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
1094 | },
1095 | "lodash.isplainobject": {
1096 | "version": "4.0.6",
1097 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
1098 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
1099 | },
1100 | "lodash.isstring": {
1101 | "version": "4.0.1",
1102 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
1103 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
1104 | },
1105 | "lodash.once": {
1106 | "version": "4.1.1",
1107 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
1108 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
1109 | },
1110 | "lru-cache": {
1111 | "version": "4.1.3",
1112 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
1113 | "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
1114 | "requires": {
1115 | "pseudomap": "^1.0.2",
1116 | "yallist": "^2.1.2"
1117 | }
1118 | },
1119 | "media-typer": {
1120 | "version": "0.3.0",
1121 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1122 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
1123 | },
1124 | "merge-descriptors": {
1125 | "version": "1.0.1",
1126 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
1127 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
1128 | },
1129 | "methods": {
1130 | "version": "1.1.2",
1131 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1132 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
1133 | },
1134 | "mime": {
1135 | "version": "1.4.1",
1136 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
1137 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
1138 | },
1139 | "mime-db": {
1140 | "version": "1.35.0",
1141 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
1142 | "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
1143 | },
1144 | "mime-types": {
1145 | "version": "2.1.19",
1146 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
1147 | "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
1148 | "requires": {
1149 | "mime-db": "~1.35.0"
1150 | }
1151 | },
1152 | "mimic-fn": {
1153 | "version": "1.2.0",
1154 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
1155 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
1156 | },
1157 | "minimatch": {
1158 | "version": "3.0.4",
1159 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1160 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1161 | "requires": {
1162 | "brace-expansion": "^1.1.7"
1163 | }
1164 | },
1165 | "minimist": {
1166 | "version": "0.0.8",
1167 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
1168 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
1169 | },
1170 | "mkdirp": {
1171 | "version": "0.5.1",
1172 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
1173 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
1174 | "requires": {
1175 | "minimist": "0.0.8"
1176 | }
1177 | },
1178 | "mongodb": {
1179 | "version": "3.1.1",
1180 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.1.1.tgz",
1181 | "integrity": "sha512-GU9oWK4pi8PC7NyGiwjFMwZyMqwGWoMEMvM0LZh7UKW/FFAqgmZKjjriD+5MEOCDUJE2dtHX93/K5UtDxO0otg==",
1182 | "requires": {
1183 | "mongodb-core": "3.1.0"
1184 | }
1185 | },
1186 | "mongodb-core": {
1187 | "version": "3.1.0",
1188 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.1.0.tgz",
1189 | "integrity": "sha512-qRjG62Fu//CZhkgn0jA/k8jh5MhACIq8cOJUryH6sck87pgt+C222MSD02tsCq5zNo/B6ZFHtNodZ2qpf8E86g==",
1190 | "requires": {
1191 | "bson": "~1.0.4",
1192 | "require_optional": "^1.0.1",
1193 | "saslprep": "^1.0.0"
1194 | }
1195 | },
1196 | "mongoose": {
1197 | "version": "5.2.6",
1198 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.2.6.tgz",
1199 | "integrity": "sha512-0W37haYSdeaD2oRT+T8A94HD9vpPvB4PptnzfnB09PTqA55aH0ASM+MZZRN81kZI72vYRqXqEwdU6gBR6R/vqw==",
1200 | "requires": {
1201 | "async": "2.6.1",
1202 | "bson": "~1.0.5",
1203 | "kareem": "2.2.1",
1204 | "lodash.get": "4.4.2",
1205 | "mongodb": "3.1.1",
1206 | "mongodb-core": "3.1.0",
1207 | "mongoose-legacy-pluralize": "1.0.2",
1208 | "mpath": "0.4.1",
1209 | "mquery": "3.1.1",
1210 | "ms": "2.0.0",
1211 | "regexp-clone": "0.0.1",
1212 | "sliced": "1.0.1"
1213 | }
1214 | },
1215 | "mongoose-legacy-pluralize": {
1216 | "version": "1.0.2",
1217 | "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
1218 | "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
1219 | },
1220 | "mpath": {
1221 | "version": "0.4.1",
1222 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.4.1.tgz",
1223 | "integrity": "sha512-NNY/MpBkALb9jJmjpBlIi6GRoLveLUM0pJzgbp9vY9F7IQEb/HREC/nxrixechcQwd1NevOhJnWWV8QQQRE+OA=="
1224 | },
1225 | "mquery": {
1226 | "version": "3.1.1",
1227 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.1.1.tgz",
1228 | "integrity": "sha512-RC8BMQJizE20bYaAiZ5uQIvuRLNo6eH6wFPoOwQbBR69dDti8Cj6d3f7pRyvbLv7WMjaQIJYo3P2kM4RUabdFg==",
1229 | "requires": {
1230 | "bluebird": "3.5.1",
1231 | "debug": "3.1.0",
1232 | "eslint": "4.14.0",
1233 | "regexp-clone": "0.0.1",
1234 | "sliced": "1.0.1"
1235 | },
1236 | "dependencies": {
1237 | "debug": {
1238 | "version": "3.1.0",
1239 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
1240 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
1241 | "requires": {
1242 | "ms": "2.0.0"
1243 | }
1244 | }
1245 | }
1246 | },
1247 | "ms": {
1248 | "version": "2.0.0",
1249 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1250 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
1251 | },
1252 | "mute-stream": {
1253 | "version": "0.0.7",
1254 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
1255 | "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
1256 | },
1257 | "natural-compare": {
1258 | "version": "1.4.0",
1259 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
1260 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
1261 | },
1262 | "negotiator": {
1263 | "version": "0.6.1",
1264 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
1265 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
1266 | },
1267 | "normalize-package-data": {
1268 | "version": "2.4.0",
1269 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
1270 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
1271 | "requires": {
1272 | "hosted-git-info": "^2.1.4",
1273 | "is-builtin-module": "^1.0.0",
1274 | "semver": "2 || 3 || 4 || 5",
1275 | "validate-npm-package-license": "^3.0.1"
1276 | }
1277 | },
1278 | "object-assign": {
1279 | "version": "4.1.1",
1280 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1281 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
1282 | },
1283 | "on-finished": {
1284 | "version": "2.3.0",
1285 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
1286 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
1287 | "requires": {
1288 | "ee-first": "1.1.1"
1289 | }
1290 | },
1291 | "once": {
1292 | "version": "1.4.0",
1293 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1294 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1295 | "requires": {
1296 | "wrappy": "1"
1297 | }
1298 | },
1299 | "onetime": {
1300 | "version": "2.0.1",
1301 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
1302 | "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
1303 | "requires": {
1304 | "mimic-fn": "^1.0.0"
1305 | }
1306 | },
1307 | "optionator": {
1308 | "version": "0.8.2",
1309 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
1310 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
1311 | "requires": {
1312 | "deep-is": "~0.1.3",
1313 | "fast-levenshtein": "~2.0.4",
1314 | "levn": "~0.3.0",
1315 | "prelude-ls": "~1.1.2",
1316 | "type-check": "~0.3.2",
1317 | "wordwrap": "~1.0.0"
1318 | }
1319 | },
1320 | "os-tmpdir": {
1321 | "version": "1.0.2",
1322 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
1323 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
1324 | },
1325 | "parse-json": {
1326 | "version": "4.0.0",
1327 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
1328 | "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
1329 | "requires": {
1330 | "error-ex": "^1.3.1",
1331 | "json-parse-better-errors": "^1.0.1"
1332 | }
1333 | },
1334 | "parseurl": {
1335 | "version": "1.3.2",
1336 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
1337 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
1338 | },
1339 | "passport": {
1340 | "version": "0.4.0",
1341 | "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
1342 | "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
1343 | "requires": {
1344 | "passport-strategy": "1.x.x",
1345 | "pause": "0.0.1"
1346 | }
1347 | },
1348 | "passport-jwt": {
1349 | "version": "4.0.0",
1350 | "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz",
1351 | "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==",
1352 | "requires": {
1353 | "jsonwebtoken": "^8.2.0",
1354 | "passport-strategy": "^1.0.0"
1355 | }
1356 | },
1357 | "passport-strategy": {
1358 | "version": "1.0.0",
1359 | "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
1360 | "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
1361 | },
1362 | "path-is-absolute": {
1363 | "version": "1.0.1",
1364 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1365 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
1366 | },
1367 | "path-is-inside": {
1368 | "version": "1.0.2",
1369 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
1370 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
1371 | },
1372 | "path-to-regexp": {
1373 | "version": "0.1.7",
1374 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
1375 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
1376 | },
1377 | "path-type": {
1378 | "version": "3.0.0",
1379 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
1380 | "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
1381 | "requires": {
1382 | "pify": "^3.0.0"
1383 | },
1384 | "dependencies": {
1385 | "pify": {
1386 | "version": "3.0.0",
1387 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
1388 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
1389 | }
1390 | }
1391 | },
1392 | "pause": {
1393 | "version": "0.0.1",
1394 | "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
1395 | "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
1396 | },
1397 | "pify": {
1398 | "version": "2.3.0",
1399 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
1400 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
1401 | },
1402 | "pinkie": {
1403 | "version": "2.0.4",
1404 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
1405 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
1406 | },
1407 | "pinkie-promise": {
1408 | "version": "2.0.1",
1409 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
1410 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
1411 | "requires": {
1412 | "pinkie": "^2.0.0"
1413 | }
1414 | },
1415 | "pluralize": {
1416 | "version": "7.0.0",
1417 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
1418 | "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
1419 | },
1420 | "prelude-ls": {
1421 | "version": "1.1.2",
1422 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
1423 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
1424 | },
1425 | "process-nextick-args": {
1426 | "version": "2.0.0",
1427 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
1428 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
1429 | },
1430 | "progress": {
1431 | "version": "2.0.0",
1432 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
1433 | "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
1434 | },
1435 | "proxy-addr": {
1436 | "version": "2.0.4",
1437 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
1438 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==",
1439 | "requires": {
1440 | "forwarded": "~0.1.2",
1441 | "ipaddr.js": "1.8.0"
1442 | }
1443 | },
1444 | "pseudomap": {
1445 | "version": "1.0.2",
1446 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
1447 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
1448 | },
1449 | "punycode": {
1450 | "version": "2.1.1",
1451 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
1452 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
1453 | },
1454 | "qs": {
1455 | "version": "6.5.2",
1456 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
1457 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
1458 | },
1459 | "range-parser": {
1460 | "version": "1.2.0",
1461 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
1462 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
1463 | },
1464 | "raw-body": {
1465 | "version": "2.3.3",
1466 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
1467 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
1468 | "requires": {
1469 | "bytes": "3.0.0",
1470 | "http-errors": "1.6.3",
1471 | "iconv-lite": "0.4.23",
1472 | "unpipe": "1.0.0"
1473 | }
1474 | },
1475 | "read-pkg": {
1476 | "version": "3.0.0",
1477 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
1478 | "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
1479 | "requires": {
1480 | "load-json-file": "^4.0.0",
1481 | "normalize-package-data": "^2.3.2",
1482 | "path-type": "^3.0.0"
1483 | }
1484 | },
1485 | "readable-stream": {
1486 | "version": "2.3.6",
1487 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
1488 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
1489 | "requires": {
1490 | "core-util-is": "~1.0.0",
1491 | "inherits": "~2.0.3",
1492 | "isarray": "~1.0.0",
1493 | "process-nextick-args": "~2.0.0",
1494 | "safe-buffer": "~5.1.1",
1495 | "string_decoder": "~1.1.1",
1496 | "util-deprecate": "~1.0.1"
1497 | }
1498 | },
1499 | "regexp-clone": {
1500 | "version": "0.0.1",
1501 | "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz",
1502 | "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk="
1503 | },
1504 | "require-uncached": {
1505 | "version": "1.0.3",
1506 | "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
1507 | "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
1508 | "requires": {
1509 | "caller-path": "^0.1.0",
1510 | "resolve-from": "^1.0.0"
1511 | },
1512 | "dependencies": {
1513 | "resolve-from": {
1514 | "version": "1.0.1",
1515 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
1516 | "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
1517 | }
1518 | }
1519 | },
1520 | "require_optional": {
1521 | "version": "1.0.1",
1522 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
1523 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
1524 | "requires": {
1525 | "resolve-from": "^2.0.0",
1526 | "semver": "^5.1.0"
1527 | }
1528 | },
1529 | "resolve-from": {
1530 | "version": "2.0.0",
1531 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
1532 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
1533 | },
1534 | "restore-cursor": {
1535 | "version": "2.0.0",
1536 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
1537 | "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
1538 | "requires": {
1539 | "onetime": "^2.0.0",
1540 | "signal-exit": "^3.0.2"
1541 | }
1542 | },
1543 | "rimraf": {
1544 | "version": "2.6.2",
1545 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
1546 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
1547 | "requires": {
1548 | "glob": "^7.0.5"
1549 | }
1550 | },
1551 | "run-async": {
1552 | "version": "2.3.0",
1553 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
1554 | "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
1555 | "requires": {
1556 | "is-promise": "^2.1.0"
1557 | }
1558 | },
1559 | "rx": {
1560 | "version": "2.3.24",
1561 | "resolved": "https://registry.npmjs.org/rx/-/rx-2.3.24.tgz",
1562 | "integrity": "sha1-FPlQpCF9fjXapxu8vljv9o6ksrc="
1563 | },
1564 | "rx-lite": {
1565 | "version": "4.0.8",
1566 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
1567 | "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ="
1568 | },
1569 | "rx-lite-aggregates": {
1570 | "version": "4.0.8",
1571 | "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
1572 | "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
1573 | "requires": {
1574 | "rx-lite": "*"
1575 | }
1576 | },
1577 | "safe-buffer": {
1578 | "version": "5.1.1",
1579 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
1580 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
1581 | },
1582 | "safer-buffer": {
1583 | "version": "2.1.2",
1584 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1585 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1586 | },
1587 | "saslprep": {
1588 | "version": "1.0.1",
1589 | "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.1.tgz",
1590 | "integrity": "sha512-ntN6SbE3hRqd45PKKadRPgA+xHPWg5lPSj2JWJdJvjTwXDDfkPVtXWvP8jJojvnm+rAsZ2b299C5NwZqq818EA==",
1591 | "optional": true
1592 | },
1593 | "semver": {
1594 | "version": "5.5.0",
1595 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
1596 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
1597 | },
1598 | "send": {
1599 | "version": "0.16.2",
1600 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
1601 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
1602 | "requires": {
1603 | "debug": "2.6.9",
1604 | "depd": "~1.1.2",
1605 | "destroy": "~1.0.4",
1606 | "encodeurl": "~1.0.2",
1607 | "escape-html": "~1.0.3",
1608 | "etag": "~1.8.1",
1609 | "fresh": "0.5.2",
1610 | "http-errors": "~1.6.2",
1611 | "mime": "1.4.1",
1612 | "ms": "2.0.0",
1613 | "on-finished": "~2.3.0",
1614 | "range-parser": "~1.2.0",
1615 | "statuses": "~1.4.0"
1616 | },
1617 | "dependencies": {
1618 | "statuses": {
1619 | "version": "1.4.0",
1620 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
1621 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
1622 | }
1623 | }
1624 | },
1625 | "serve-static": {
1626 | "version": "1.13.2",
1627 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
1628 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
1629 | "requires": {
1630 | "encodeurl": "~1.0.2",
1631 | "escape-html": "~1.0.3",
1632 | "parseurl": "~1.3.2",
1633 | "send": "0.16.2"
1634 | }
1635 | },
1636 | "setprototypeof": {
1637 | "version": "1.1.0",
1638 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
1639 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
1640 | },
1641 | "shebang-command": {
1642 | "version": "1.2.0",
1643 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1644 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
1645 | "requires": {
1646 | "shebang-regex": "^1.0.0"
1647 | }
1648 | },
1649 | "shebang-regex": {
1650 | "version": "1.0.0",
1651 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1652 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
1653 | },
1654 | "signal-exit": {
1655 | "version": "3.0.2",
1656 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
1657 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
1658 | },
1659 | "slice-ansi": {
1660 | "version": "1.0.0",
1661 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
1662 | "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==",
1663 | "requires": {
1664 | "is-fullwidth-code-point": "^2.0.0"
1665 | }
1666 | },
1667 | "sliced": {
1668 | "version": "1.0.1",
1669 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
1670 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
1671 | },
1672 | "spawn-command": {
1673 | "version": "0.0.2-1",
1674 | "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
1675 | "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A="
1676 | },
1677 | "spdx-correct": {
1678 | "version": "3.0.0",
1679 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz",
1680 | "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==",
1681 | "requires": {
1682 | "spdx-expression-parse": "^3.0.0",
1683 | "spdx-license-ids": "^3.0.0"
1684 | }
1685 | },
1686 | "spdx-exceptions": {
1687 | "version": "2.1.0",
1688 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz",
1689 | "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg=="
1690 | },
1691 | "spdx-expression-parse": {
1692 | "version": "3.0.0",
1693 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
1694 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
1695 | "requires": {
1696 | "spdx-exceptions": "^2.1.0",
1697 | "spdx-license-ids": "^3.0.0"
1698 | }
1699 | },
1700 | "spdx-license-ids": {
1701 | "version": "3.0.0",
1702 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz",
1703 | "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA=="
1704 | },
1705 | "sprintf-js": {
1706 | "version": "1.0.3",
1707 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
1708 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
1709 | },
1710 | "statuses": {
1711 | "version": "1.5.0",
1712 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
1713 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
1714 | },
1715 | "string-width": {
1716 | "version": "2.1.1",
1717 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
1718 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
1719 | "requires": {
1720 | "is-fullwidth-code-point": "^2.0.0",
1721 | "strip-ansi": "^4.0.0"
1722 | }
1723 | },
1724 | "string_decoder": {
1725 | "version": "1.1.1",
1726 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
1727 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
1728 | "requires": {
1729 | "safe-buffer": "~5.1.0"
1730 | }
1731 | },
1732 | "strip-ansi": {
1733 | "version": "4.0.0",
1734 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
1735 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
1736 | "requires": {
1737 | "ansi-regex": "^3.0.0"
1738 | },
1739 | "dependencies": {
1740 | "ansi-regex": {
1741 | "version": "3.0.0",
1742 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
1743 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
1744 | }
1745 | }
1746 | },
1747 | "strip-bom": {
1748 | "version": "3.0.0",
1749 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
1750 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
1751 | },
1752 | "strip-json-comments": {
1753 | "version": "2.0.1",
1754 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
1755 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
1756 | },
1757 | "supports-color": {
1758 | "version": "2.0.0",
1759 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1760 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
1761 | },
1762 | "table": {
1763 | "version": "4.0.3",
1764 | "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz",
1765 | "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==",
1766 | "requires": {
1767 | "ajv": "^6.0.1",
1768 | "ajv-keywords": "^3.0.0",
1769 | "chalk": "^2.1.0",
1770 | "lodash": "^4.17.4",
1771 | "slice-ansi": "1.0.0",
1772 | "string-width": "^2.1.1"
1773 | },
1774 | "dependencies": {
1775 | "ajv": {
1776 | "version": "6.5.2",
1777 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz",
1778 | "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==",
1779 | "requires": {
1780 | "fast-deep-equal": "^2.0.1",
1781 | "fast-json-stable-stringify": "^2.0.0",
1782 | "json-schema-traverse": "^0.4.1",
1783 | "uri-js": "^4.2.1"
1784 | }
1785 | },
1786 | "fast-deep-equal": {
1787 | "version": "2.0.1",
1788 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
1789 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
1790 | },
1791 | "json-schema-traverse": {
1792 | "version": "0.4.1",
1793 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
1794 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
1795 | }
1796 | }
1797 | },
1798 | "text-table": {
1799 | "version": "0.2.0",
1800 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
1801 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
1802 | },
1803 | "through": {
1804 | "version": "2.3.8",
1805 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
1806 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
1807 | },
1808 | "tmp": {
1809 | "version": "0.0.33",
1810 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
1811 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
1812 | "requires": {
1813 | "os-tmpdir": "~1.0.2"
1814 | }
1815 | },
1816 | "tree-kill": {
1817 | "version": "1.2.0",
1818 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz",
1819 | "integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg=="
1820 | },
1821 | "type-check": {
1822 | "version": "0.3.2",
1823 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
1824 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
1825 | "requires": {
1826 | "prelude-ls": "~1.1.2"
1827 | }
1828 | },
1829 | "type-is": {
1830 | "version": "1.6.16",
1831 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
1832 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
1833 | "requires": {
1834 | "media-typer": "0.3.0",
1835 | "mime-types": "~2.1.18"
1836 | }
1837 | },
1838 | "typedarray": {
1839 | "version": "0.0.6",
1840 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
1841 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
1842 | },
1843 | "unpipe": {
1844 | "version": "1.0.0",
1845 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1846 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
1847 | },
1848 | "uri-js": {
1849 | "version": "4.2.2",
1850 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
1851 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
1852 | "requires": {
1853 | "punycode": "^2.1.0"
1854 | }
1855 | },
1856 | "util-deprecate": {
1857 | "version": "1.0.2",
1858 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1859 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
1860 | },
1861 | "utils-merge": {
1862 | "version": "1.0.1",
1863 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1864 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
1865 | },
1866 | "validate-npm-package-license": {
1867 | "version": "3.0.4",
1868 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
1869 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
1870 | "requires": {
1871 | "spdx-correct": "^3.0.0",
1872 | "spdx-expression-parse": "^3.0.0"
1873 | }
1874 | },
1875 | "validator": {
1876 | "version": "10.5.0",
1877 | "resolved": "https://registry.npmjs.org/validator/-/validator-10.5.0.tgz",
1878 | "integrity": "sha512-6OOi+eV2mOxCFLq0f2cJDrdB6lrtLXEUxabhNRGjgOLT/l3SSll9J49Cl+LIloUqkWWTPraK/mucEQ3dc2jStQ=="
1879 | },
1880 | "vary": {
1881 | "version": "1.1.2",
1882 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1883 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
1884 | },
1885 | "which": {
1886 | "version": "1.3.1",
1887 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1888 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1889 | "requires": {
1890 | "isexe": "^2.0.0"
1891 | }
1892 | },
1893 | "wordwrap": {
1894 | "version": "1.0.0",
1895 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
1896 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
1897 | },
1898 | "wrappy": {
1899 | "version": "1.0.2",
1900 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1901 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1902 | },
1903 | "write": {
1904 | "version": "0.2.1",
1905 | "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
1906 | "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
1907 | "requires": {
1908 | "mkdirp": "^0.5.1"
1909 | }
1910 | },
1911 | "yallist": {
1912 | "version": "2.1.2",
1913 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
1914 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
1915 | }
1916 | }
1917 | }
1918 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mern",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "client-install": "npm install --prefix client",
8 | "start": "node server.js",
9 | "server": "nodemon server",
10 | "client": "npm start --prefix client",
11 | "dev": "concurrently \"npm run server\" \"npm run client\""
12 | },
13 | "author": "Niccu Bagonoc",
14 | "license": "ISC",
15 | "dependencies": {
16 | "bcryptjs": "^2.4.3",
17 | "body-parser": "^1.18.3",
18 | "concurrently": "^3.6.1",
19 | "cors": "^2.8.4",
20 | "express": "^4.16.3",
21 | "jsonwebtoken": "^8.3.0",
22 | "mongoose": "^5.1.5",
23 | "passport": "^0.4.0",
24 | "passport-jwt": "^4.0.0",
25 | "validator": "^10.5.0"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/routes/api/auth.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const mongoose = require("mongoose");
4 | const bcrypt = require("bcryptjs");
5 | const jwt = require("jsonwebtoken");
6 | // const passport = require("passport");
7 | const validator = require("validator");
8 | const isEmpty = require("../../utils/isEmpty");
9 | const key = require("../../config/dbSecretKeys");
10 |
11 | // bring in user model
12 | require("../../models/User");
13 | const User = mongoose.model("users");
14 |
15 | // POST | api/auth/register
16 | // register process
17 | router.post("/register", (req, res, next) => {
18 | const { errors, isValid } = validateRegister(req.body);
19 |
20 | // Register validation
21 | function validateRegister(data) {
22 | let errors = {};
23 |
24 | // check if data send is ""
25 | data.name = !isEmpty(data.name) ? data.name : "";
26 | data.email = !isEmpty(data.email) ? data.email : "";
27 | data.password = !isEmpty(data.password) ? data.password : "";
28 | data.password2 = !isEmpty(data.password2) ? data.password2 : "";
29 |
30 | // validation using validator
31 | if (validator.isEmpty(data.name)) {
32 | errors.name = "name is required";
33 | }
34 | if (validator.isEmpty(data.email)) {
35 | errors.email = "email is required";
36 | }
37 | if (!validator.isEmail(data.email)) {
38 | errors.email = "email is not valid";
39 | }
40 | if (validator.isEmpty(data.password)) {
41 | errors.password = "password is required";
42 | }
43 | if (validator.isEmpty(data.password2)) {
44 | errors.password2 = "confirm password is required";
45 | }
46 | if (!validator.equals(data.password, data.password2)) {
47 | errors.password2 = "confirm password did not match";
48 | }
49 | return {
50 | errors,
51 | isValid: isEmpty(errors)
52 | };
53 | }
54 |
55 | if (!isValid) {
56 | return res.status(400).json(errors);
57 | } else {
58 | User.findOne({ email: req.body.email })
59 | .then(user => {
60 | if (user) {
61 | errors.email = "Email already exists";
62 | return res.status(400).json(errors);
63 | } else {
64 | const newUser = new User({
65 | name: req.body.name,
66 | email: req.body.email,
67 | password: req.body.password
68 | });
69 | bcrypt.genSalt(10, (err, salt) => {
70 | bcrypt.hash(newUser.password, salt, (err, hash) => {
71 | if (err) {
72 | res.json({ success: false, msg: "Failed to register user" });
73 | } else {
74 | newUser.password = hash;
75 | newUser
76 | .save()
77 | .then(user => {
78 | res.json({ success: true, msg: "User registered" });
79 | })
80 | .catch(ex => {
81 | return res.status(500).send("Something went wrong");
82 | });
83 | }
84 | });
85 | });
86 | }
87 | })
88 | .catch(ex => {
89 | return res.status(500).send("Something went wrong");
90 | });
91 | }
92 | });
93 |
94 | // POST | api/auth/login
95 | // Login process
96 | router.post("/login", (req, res, next) => {
97 | const { errors, isValid } = validateLogin(req.body);
98 |
99 | // Login validation
100 | function validateLogin(data) {
101 | let errors = {};
102 |
103 | if (validator.isEmpty(data.email)) {
104 | errors.email = "email is required";
105 | }
106 | if (!validator.isEmail(data.email)) {
107 | errors.email = "email is not valid";
108 | }
109 | if (validator.isEmpty(data.password)) {
110 | errors.password = "password is required";
111 | }
112 | return {
113 | errors,
114 | isValid: isEmpty(errors)
115 | };
116 | }
117 |
118 | if (!isValid) {
119 | return res.status(400).json(errors);
120 | } else {
121 | const email = req.body.email;
122 | const password = req.body.password;
123 |
124 | User.findOne({ email })
125 | .then(user => {
126 | // check for user
127 | if (!user) {
128 | errors.email = "User does not exist";
129 | return res.status(400).json(errors);
130 | } else {
131 | // check password
132 | bcrypt
133 | .compare(password, user.password)
134 | .then(isMatch => {
135 | if (isMatch) {
136 | // user matched
137 | const payload = {
138 | id: user.id,
139 | name: user.name,
140 | role: user.role
141 | };
142 | // create JWT payload
143 | // sign token
144 | jwt.sign(
145 | payload,
146 | key.secretOrKey,
147 | { expiresIn: 86400 },
148 | (err, token) => {
149 | res.json({
150 | success: true,
151 | token: "JWT " + token
152 | });
153 | }
154 | );
155 | } else {
156 | errors.password = "Password incorrect";
157 | return res.status(400).json(errors);
158 | }
159 | })
160 | .catch(ex => {
161 | return res.status(500).send("Something went wrong");
162 | });
163 | }
164 | })
165 | .catch(ex => {
166 | return res.status(500).send("Something went wrong");
167 | });
168 | }
169 | });
170 |
171 | // test if the backend is secured
172 | // router.get(
173 | // "/test",
174 | // passport.authenticate("jwt", { session: false }),
175 | // (req, res) => {
176 | // res.json({ message: "you are authorized" });
177 | // }
178 | // );
179 |
180 | module.exports = router;
181 |
--------------------------------------------------------------------------------
/routes/api/users.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 | const mongoose = require("mongoose");
4 | const passport = require("passport");
5 | const isAdmin = require("../../guards/isAdmin");
6 | const isModerator = require("../../guards/isModerator");
7 |
8 | // bring in user model
9 | require("../../models/User");
10 | const User = mongoose.model("users");
11 |
12 | // GET | api/users/profile
13 | // view current user profile
14 | router.get(
15 | "/profile",
16 | passport.authenticate("jwt", { session: false }),
17 | (req, res) => {
18 | User.findOne({ _id: req.user.id })
19 | .then(user => {
20 | if (user) {
21 | res.json({ success: true, user });
22 | } else {
23 | res.json({ success: false, message: "User not found" });
24 | }
25 | })
26 | .catch(ex => {
27 | return res.status(500).send("Something went wrong");
28 | });
29 | }
30 | );
31 |
32 | // GET | api/users
33 | // view users list
34 | router.get(
35 | "/",
36 | [passport.authenticate("jwt", { session: false }), isAdmin],
37 | (req, res) => {
38 | User.find({ role: "subscriber" })
39 | .then(users => {
40 | if (users) {
41 | res.json({ success: true, users });
42 | } else {
43 | res.json({ success: false, message: "Users not found" });
44 | }
45 | })
46 | .catch(ex => {
47 | return res.status(500).send("Something went wrong");
48 | });
49 | }
50 | );
51 |
52 | // GET | api/users/view/:id
53 | // get user
54 | router.get(
55 | "/show/:id",
56 | [passport.authenticate("jwt", { session: false }), isAdmin],
57 | (req, res) => {
58 | User.findOne({ _id: req.params.id })
59 | .then(user => {
60 | if (user) {
61 | res.json({ success: true, user });
62 | } else {
63 | res.json({ success: false, message: "User not found" });
64 | }
65 | })
66 | .catch(ex => {
67 | return res.status(500).send("Something went wrong");
68 | });
69 | }
70 | );
71 |
72 | // PUT | api/users/update
73 | // update user
74 | router.put(
75 | "/update/:id",
76 | [passport.authenticate("jwt", { session: false }), isAdmin],
77 | (req, res) => {
78 | if (!req.body.name) {
79 | res.json({ success: false, msg: "name is required" });
80 | } else {
81 | User.findOne({ _id: req.params.id })
82 | .then(user => {
83 | if (user) {
84 | user.name = req.body.name;
85 | user
86 | .save()
87 | .then(userUpdated => {
88 | if (userUpdated) {
89 | res.json({ success: true, message: "User updated!" });
90 | } else {
91 | res.json({
92 | success: false,
93 | message: "User was not updated. Please try again"
94 | });
95 | }
96 | })
97 | .catch(ex => {
98 | return res.status(500).send("Something went wrong");
99 | });
100 | } else {
101 | res.json({ success: false, message: "User not found" });
102 | }
103 | })
104 | .catch(ex => {
105 | return res.status(500).send("Something went wrong");
106 | });
107 | }
108 | }
109 | );
110 |
111 | // DELETE | api/users/delete/:id
112 | // delete user
113 | router.delete(
114 | "/delete/:id",
115 | [passport.authenticate("jwt", { session: false }), isAdmin],
116 | (req, res) => {
117 | User.findOne({ _id: req.params.id })
118 | .then(user => {
119 | if (user) {
120 | user
121 | .remove()
122 | .then(userDeleted => {
123 | if (userDeleted) {
124 | res.json({ success: true, message: "User deleted" });
125 | } else {
126 | res.json({ success: false, message: "User was not deleted" });
127 | }
128 | })
129 | .catch(ex => {
130 | return res.status(500).send("Something went wrong");
131 | });
132 | } else {
133 | res.json({ success: false, message: "User not found" });
134 | }
135 | })
136 | .catch(ex => {
137 | return res.status(500).send("Something went wrong");
138 | });
139 | }
140 | );
141 |
142 | module.exports = router;
143 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const mongoose = require("mongoose");
3 | const passport = require("passport");
4 | const bodyParser = require("body-parser");
5 | const path = require("path");
6 | const cors = require("cors");
7 |
8 | // INITIALIZE APP
9 | const app = express();
10 |
11 | // MODELS
12 | require("./models/User");
13 |
14 | // MIDDLEWARES
15 | // cors
16 | app.use(cors());
17 | // body parser middleware
18 | app.use(bodyParser.urlencoded({ extended: false }));
19 | app.use(bodyParser.json());
20 | // passport middleware
21 | app.use(passport.initialize());
22 | app.use(passport.session());
23 |
24 | // CONFIGS
25 | // mongoDB;
26 | const db = require("./config/dbSecretKeys").mongoURI;
27 | // Passport config
28 | require("./config/passport")(passport);
29 |
30 | // CONNECT TO DB
31 | mongoose
32 | .connect(db)
33 | .then(() => console.log("we are connected to our DB"))
34 | .catch(err => console.log(err));
35 |
36 | // ROUTES
37 | const auth = require("./routes/api/auth");
38 | const users = require("./routes/api/users");
39 |
40 | // USE ROUTES
41 | app.use("/api/auth", auth);
42 | app.use("/api/users", users);
43 |
44 | // STATIC FOLDER
45 | app.use(express.static(path.join(__dirname, "public")));
46 |
47 | // USE ANGULAR AS FRONTEND
48 | app.get("*", (req, res) => {
49 | res.sendFile(path.join(__dirname, "public", "index.html"));
50 | });
51 |
52 | // SET PORT
53 | const port = process.env.PORT || 5000;
54 | app.listen(port, () => {
55 | console.log(`we are live at ${port}`);
56 | });
57 |
--------------------------------------------------------------------------------
/utils/isEmpty.js:
--------------------------------------------------------------------------------
1 | const isEmpty = value =>
2 | value === undefined ||
3 | value === null ||
4 | (typeof value === "object" && Object.keys(value).length === 0) ||
5 | (typeof value === "string" && value.trim().length === 0);
6 | module.exports = isEmpty;
7 |
--------------------------------------------------------------------------------