erge branch 'master' of https://github.com/AdvancedAlgos/UsersModule
This commit is contained in:
commit
0669921d0e
24 files changed
+465
-300
No files matched your search
@@ -20,9 +20,9 @@ App.js
|
||||
| | |
|
||||
| | |- UserTabs
|
||||
| | | |
|
||||
| | | |- Tab 1 - AddUser
|
||||
| | | |- Tab 1 - UserUpdate
|
||||
| | | |
|
||||
| | | |- Tab 2 - UpdateUser
|
||||
| | | |- Tab 2 - ManageImages
|
||||
| |
|
||||
| |- Browse
|
||||
| | |
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import Post from './components/Post';
|
||||
import Footer from './components/Footer';
|
||||
import Callback from './components/Callback';
|
||||
|
||||
import Auth from './auth/index';
|
||||
import Auth from './auth/Auth';
|
||||
|
||||
// Apollo Client Setup
|
||||
const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql', changeOrigin: true })
|
||||
|
||||
@@ -8,8 +8,6 @@ import { client } from '../App'
|
||||
|
||||
import { AUTH_CONFIG } from './Auth0' // create by renaming Auth0.sample.js to Auth0.js and setting vars
|
||||
|
||||
console.log(process.env.AUTH0_CLIENTID)
|
||||
|
||||
const AUTHENTICATE = gql`
|
||||
mutation authenticate($idToken: String!) {
|
||||
authenticate(idToken: $idToken) {
|
||||
@@ -128,7 +126,7 @@ class Auth {
|
||||
})
|
||||
|
||||
console.log('signinOrCreateAccount auth: ', await data)
|
||||
setItem('user', data.data.authenticate.authId)
|
||||
setItem('user', JSON.stringify(data.data.authenticate))
|
||||
if (window.location.href.includes(`callback`)) {
|
||||
window.location.href = '/'
|
||||
} else {
|
||||
@@ -3,9 +3,9 @@ import React from 'react'
|
||||
const About = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className="container">
|
||||
<h4 className="center">About</h4>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Recusandae repudiandae repellat illo magni eligendi cupiditate voluptates eius nam voluptate. Incidunt nihil ullam quae quia officia quaerat, deserunt eligendi explicabo totam?</p>
|
||||
<div>
|
||||
<h4>About</h4>
|
||||
<p>This Module was developed by the AATeam. Contributions are welcomed.</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import {graphql, compose} from 'react-apollo';
|
||||
import {getRolesQuery, addUserMutation, getUsersQuery} from '../queries/queries';
|
||||
|
||||
import AddUserNextButton from './AddUserNextButton';
|
||||
|
||||
class AddUser extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
alias: '',
|
||||
authId: '1'
|
||||
};
|
||||
}
|
||||
|
||||
submitForm(e){
|
||||
|
||||
e.preventDefault();
|
||||
this.props.addUserMutation({
|
||||
variables: {
|
||||
alias: this.state.alias,
|
||||
authId: this.state.authId
|
||||
},
|
||||
refetchQueries: [{ query: getUsersQuery}] // This allow us to re run whatever queries are necesary after the mutation.
|
||||
});
|
||||
this.props.onAdded();
|
||||
}
|
||||
|
||||
render(){
|
||||
return(
|
||||
<div>
|
||||
<form onSubmit={this.submitForm.bind(this)}>
|
||||
<p>Choose an Alias that will identify you anonimously across the whole Advanced Algos ecosystem. Choose it carefully, since the the Alias can not be changed later.</p>
|
||||
<div >
|
||||
<div >
|
||||
<input id="alias" type="text" onChange={ (e) => this.setState({ alias:e.target.value})}/>
|
||||
<label htmlFor="alias">Alias</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<AddUserNextButton/>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
graphql(getRolesQuery, {name: "getRolesQuery"}),
|
||||
graphql(addUserMutation, {name: "addUserMutation"})
|
||||
) (AddUser); // This technique binds more than one query to a single component.
|
||||
@@ -14,7 +14,6 @@ const Footer = () => {
|
||||
<h5 className="white-text">Links</h5>
|
||||
<ul className="right hide-on-med-and-down">
|
||||
<li><NavLink exact to="/">Home</NavLink></li>
|
||||
<li><NavLink to='/user'>Profile</NavLink></li>
|
||||
<li><NavLink to='/browse'>Browse</NavLink></li>
|
||||
<li><NavLink to='/search'>Search</NavLink></li>
|
||||
<li><NavLink to='/contact'>Contact</NavLink></li>
|
||||
|
||||
@@ -7,8 +7,6 @@ import React, { Component } from 'react'
|
||||
// Images
|
||||
|
||||
import PortraitImage from '../img/portrait.jpg'
|
||||
import CityImage from '../img/city.jpg'
|
||||
import NatureImage from '../img/nature.jpg'
|
||||
|
||||
class Home extends Component {
|
||||
|
||||
@@ -27,24 +25,6 @@ class Home extends Component {
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at lacus congue, suscipit elit nec, tincidunt orci.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col s12 l4 offset-l1 push-l7">
|
||||
<img src={CityImage} alt="" className="responsive-img materialboxed"></img>
|
||||
</div>
|
||||
<div className="col s12 l6 offset-l1 pull-l5 right-align">
|
||||
<h2 className="indigo-text text-darken-4">Title 2</h2>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at lacus congue, suscipit elit nec, tincidunt orci.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col s12 l4">
|
||||
<img src={NatureImage} alt="" className="responsive-img materialboxed"></img>
|
||||
</div>
|
||||
<div className="col s12 l6 offset-l1">
|
||||
<h2 className="indigo-text text-darken-4">Title 3</h2>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum at lacus congue, suscipit elit nec, tincidunt orci.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@ class LoggedInUser extends Component {
|
||||
|
||||
if(user){
|
||||
|
||||
console.log(user.firstName);
|
||||
console.log(user.lastName );
|
||||
console.log(user.alias);
|
||||
|
||||
let displayName = "No Display Name";
|
||||
|
||||
if (
|
||||
@@ -38,7 +34,7 @@ class LoggedInUser extends Component {
|
||||
|
||||
return(
|
||||
<div>
|
||||
<p><LoggedInUserMenu menuLabel={ displayName }/></p>
|
||||
<p><LoggedInUserMenu menuLabel={ displayName } user={ this.props.data.userByAuthId }/></p>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -19,11 +19,16 @@ class LoggedInUserMenu extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
property: 'value'
|
||||
user: {}
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.setState({user: this.props.user});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<WithState>
|
||||
{({ anchorEl, updateAnchorEl }) => {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
import {Redirect} from 'react-router';
|
||||
import {auth} from '../App';
|
||||
|
||||
class Logout extends Component {
|
||||
render() {
|
||||
window.localStorage.removeItem("user");
|
||||
//window.localStorage.removeItem("user");
|
||||
auth.logout();
|
||||
|
||||
return <Redirect to='/' />
|
||||
}
|
||||
|
||||
@@ -49,24 +49,21 @@ class NavBar extends Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
/*
|
||||
this._asyncRequest = window.localStorage.getItem('user').then(
|
||||
response => {
|
||||
this._asyncRequest = null;
|
||||
let user = JSON.parse(response)
|
||||
if (user) {
|
||||
const authId = user.sub;
|
||||
this.setState({ authId: authId });
|
||||
}
|
||||
}
|
||||
);
|
||||
*/
|
||||
|
||||
const userStored = localStorage.getItem('user');
|
||||
console.log(userStored);
|
||||
|
||||
if (userStored !== null && userStored !== undefined && userStored !== 'undefined') {
|
||||
const user = JSON.parse(userStored);
|
||||
const authId = user.sub;
|
||||
|
||||
/* For some reason, the result of GraphQL some times varies, that is why I had to do the following hack. */
|
||||
|
||||
let authId;
|
||||
if (user.authId === undefined) {
|
||||
authId = user.sub;
|
||||
} else {
|
||||
authId = user.authId;
|
||||
}
|
||||
|
||||
this.setState({ authId: authId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react'
|
||||
|
||||
const UserImages = () => {
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<h4>Images Manager</h4>
|
||||
<p>This functionality has not been developed yet. Please visit this section later.</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserImages
|
||||
@@ -4,15 +4,14 @@ import { withStyles } from '@material-ui/core/styles';
|
||||
import AppBar from '@material-ui/core/AppBar';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import AddIcon from '@material-ui/icons/Add';
|
||||
import UpdateIcon from '@material-ui/icons/Create';
|
||||
import ImageIcon from '@material-ui/icons/Wallpaper';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
// Components
|
||||
|
||||
import AddUser from './AddUser';
|
||||
import UpdateUser from './UpdateUser';
|
||||
import UserUpdate from './UserUpdate';
|
||||
import UserImages from './UserImages';
|
||||
|
||||
function TabContainer(props) {
|
||||
return (
|
||||
@@ -36,23 +35,16 @@ const styles = theme => ({
|
||||
|
||||
class UserTabs extends React.Component {
|
||||
state = {
|
||||
value: 0,
|
||||
cureateDisabled: "false"
|
||||
value: 0
|
||||
};
|
||||
|
||||
handleChange = (event, value) => {
|
||||
this.setState({ value });
|
||||
};
|
||||
|
||||
updateUser = () => {
|
||||
this.setState({ value: 1, cureateDisabled: "true" });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes } = this.props;
|
||||
const { value } = this.state;
|
||||
const { createDisabled } = this.state;
|
||||
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
@@ -65,16 +57,12 @@ class UserTabs extends React.Component {
|
||||
indicatorColor="primary"
|
||||
textColor="primary"
|
||||
>
|
||||
<Tab label="Create Profile" icon={<AddIcon />} />
|
||||
<Tab disabled={createDisabled} label="Create Profile" icon={<AddIcon />} />
|
||||
<Tab label="Update Profile" icon={<UpdateIcon />} />
|
||||
<Tab label="Manage Images" icon={<ImageIcon />} />
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
{value === 0 && <TabContainer><AddUser onAdded={this.updateUser}/></TabContainer>}
|
||||
{value === 1 && <TabContainer><UpdateUser/></TabContainer>}
|
||||
{value === 2 && <TabContainer>Item Three</TabContainer>}
|
||||
|
||||
{value === 0 && <TabContainer><UserUpdate/></TabContainer>}
|
||||
{value === 1 && <TabContainer><UserImages/></TabContainer>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import ReactDOM from 'react-dom';
|
||||
import {graphql, compose} from 'react-apollo';
|
||||
import {getRolesQuery, updateUserMutation, getUsersQuery} from '../queries/queries';
|
||||
|
||||
class UpdateUser extends Component {
|
||||
class UserUpdate extends Component {
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
@@ -115,66 +115,67 @@ class UpdateUser extends Component {
|
||||
}
|
||||
|
||||
render(){
|
||||
console.log("user at render", this.props);
|
||||
return(
|
||||
<div className="row">
|
||||
<form className="col s12" onSubmit={this.submitForm.bind(this)}>
|
||||
<div>
|
||||
<form onSubmit={this.submitForm.bind(this)}>
|
||||
<p>Complete your profile with the following optional information. Providing your real name might help other users trust you more.</p>
|
||||
<div className="row">
|
||||
<div className="input-field col s6">
|
||||
<input id="firstName" type="text" className="validate" onChange={ (e) => this.setState({ firstName:e.target.value})}/>
|
||||
<div>
|
||||
<div>
|
||||
<input id="firstName" type="text" onChange={ (e) => this.setState({ firstName:e.target.value})}/>
|
||||
<label htmlFor="firstName">First Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s6">
|
||||
<input id="middleName" type="text" className="validate" onChange={ (e) => this.setState({ middleName:e.target.value})}/>
|
||||
<div>
|
||||
<div>
|
||||
<input id="middleName" type="text" onChange={ (e) => this.setState({ middleName:e.target.value})}/>
|
||||
<label htmlFor="middleName">Middle Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s6">
|
||||
<input id="last_name" type="text" className="validate" onChange={ (e) => this.setState({ lastName:e.target.value})}/>
|
||||
<div>
|
||||
<div>
|
||||
<input id="last_name" type="text" onChange={ (e) => this.setState({ lastName:e.target.value})}/>
|
||||
<label htmlFor="last_name">Last Name</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s6">
|
||||
<input id="email" type="text" className="validate" onChange={ (e) => this.setState({ email:e.target.value})}/>
|
||||
<div>
|
||||
<div>
|
||||
<input id="email" type="text" onChange={ (e) => this.setState({ email:e.target.value})}/>
|
||||
<label htmlFor="email">email</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s12">
|
||||
<div>
|
||||
<div>
|
||||
<input id="emailVerified" type="checkbox" disabled/>
|
||||
<label htmlFor="emailVerified">Email Verified</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s12">
|
||||
<div>
|
||||
<div>
|
||||
<input id="isDeveloper" type="checkbox" ref="id2" onChange={this.handleCheckBoxes.bind(this)}/>
|
||||
<label htmlFor="isDeveloper">Developer</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s12">
|
||||
<div>
|
||||
<div>
|
||||
<input id="isTrader" type="checkbox" ref="id3" onChange={this.handleCheckBoxes.bind(this)}/>
|
||||
<label htmlFor="isTrader">Trader</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="input-field col s12">
|
||||
<div>
|
||||
<div>
|
||||
<input id="isDataAnalyst" type="checkbox" ref="id4" onChange={this.handleCheckBoxes.bind(this)}/>
|
||||
<label htmlFor="isDataAnalyst">Data Analyst</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div>
|
||||
<select id="role" ref="select" onChange={this.handleSelect.bind(this)}>
|
||||
{ this.displayRoles() }
|
||||
</select>
|
||||
<label htmlFor="role">Current Role:</label>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div>
|
||||
<button>Update</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -188,4 +189,4 @@ class UpdateUser extends Component {
|
||||
export default compose(
|
||||
graphql(getRolesQuery, {name: "getRolesQuery"}),
|
||||
graphql(updateUserMutation, {name: "updateUserMutation"})
|
||||
) (UpdateUser); // This technique binds more than one query to a single component.
|
||||
) (UserUpdate); // This technique binds more than one query to a single component.
|
||||
@@ -1,17 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
const Rainbow = (WrappedComponent) => {
|
||||
|
||||
const colours = ['red', 'pink', 'orange', 'blue', 'green', 'yellow'];
|
||||
const randomColour = colours[Math.floor(Math.random() * 6)];
|
||||
const className = randomColour + '-text';
|
||||
|
||||
return (props) => (
|
||||
<div className={className}>
|
||||
<WrappedComponent {...props} />
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default Rainbow
|
||||
@@ -2,12 +2,5 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
//import {createStore} from 'redux';
|
||||
//import {Provider} from 'reaxt-redux';
|
||||
//import rootReducer from './reducers/rootReducer';
|
||||
|
||||
//const store = createStore(rootReducer);
|
||||
|
||||
//ReactDOM.render(<Provider store={store}<App /></Provider>, document.getElementById('root'));
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,15 +0,0 @@
|
||||
const initState = {
|
||||
user: {}
|
||||
}
|
||||
|
||||
const rootReducer = (state = initState, action) => {
|
||||
|
||||
if(action.type === 'USER_LOGS_IN'){
|
||||
return {
|
||||
user: action.user
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export default rootReducer
|
||||
+7
-2
@@ -1,3 +1,8 @@
|
||||
|
||||
/* This module imports */
|
||||
|
||||
const globals = require('./globals');
|
||||
const sessions = require('./sessions');
|
||||
const express = require('express');
|
||||
const graphqlHTTP = require('express-graphql');
|
||||
const schema = require('./schema/schema');
|
||||
@@ -19,6 +24,8 @@ mongoose.connection.once('open', () => {
|
||||
console.log('Connected to database');
|
||||
})
|
||||
|
||||
/* Here we bind all requests to this endpoint to be procecced by the GraphQL Library. */
|
||||
|
||||
app.get('/graphql', graphqlHTTP({
|
||||
schema,
|
||||
graphiql: true
|
||||
@@ -39,8 +46,6 @@ app.post('/graphql', checkJwt, (err, req, res, next) => {
|
||||
|
||||
app.post('/graphql', (req, res, done) => getUser(req, res, done));
|
||||
|
||||
|
||||
|
||||
app.listen(4000,() => {
|
||||
console.log('Now listening for requests on port 4000');
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
const _get = require('lodash.get')
|
||||
const validateParseIdToken = require('./validate-auth0-token')
|
||||
const createUser = require('./index')
|
||||
|
||||
const userLocationOnContext = 'request.user'
|
||||
const bearerAccessToken = 'request.headers.authorization'
|
||||
|
||||
const ctxUser = ctx => _get(ctx, userLocationOnContext)
|
||||
const ctxToken = ctx => _get(ctx, bearerAccessToken)
|
||||
|
||||
const isLoggedIn = async ctx => {
|
||||
let user = ctxUser(ctx, userLocationOnContext)
|
||||
let token = ctxToken(ctx, bearerAccessToken)
|
||||
let userToken
|
||||
|
||||
if (!user && token) {
|
||||
let scheme, credentials
|
||||
const tokenParts = token.split(' ')
|
||||
if (tokenParts.length === 2) {
|
||||
scheme = tokenParts[0]
|
||||
credentials = tokenParts[1]
|
||||
}
|
||||
|
||||
if (/^Bearer$/i.test(scheme)) {
|
||||
token = credentials
|
||||
//verify token
|
||||
try {
|
||||
userToken = await validateParseIdToken(token)
|
||||
const auth0id = userToken.sub
|
||||
|
||||
user = await ctx.db.query.user({ where: { auth0id } })
|
||||
|
||||
if (!user) {
|
||||
user = await createUser(ctx, userToken)
|
||||
}
|
||||
} catch (err) {
|
||||
userToken = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
throw new Error(`Not logged in`)
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
|
||||
const isRequestingUserAlsoOwner = ({ ctx, userId, type, typeId }) =>
|
||||
ctx.db.exists[type]({ id: typeId, owner: { auth0id: userId } })
|
||||
const isRequestingUser = ({ ctx, userId }) => ctx.db.exists.User({ auth0id: userId })
|
||||
|
||||
const directiveResolvers = {
|
||||
isAuthenticated: async (next, source, args, ctx) => {
|
||||
let result = await isLoggedIn(ctx)
|
||||
console.log('directive isAuthenticated: ', result)
|
||||
return next(result)
|
||||
},
|
||||
hasRole: (next, source, { roles }, ctx) => {
|
||||
const { role } = isLoggedIn(ctx)
|
||||
console.log('directive hasRole: ', role)
|
||||
if (roles.includes(role)) {
|
||||
return next()
|
||||
}
|
||||
throw new Error(`Unauthorized, incorrect role`)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { directiveResolvers }
|
||||
@@ -0,0 +1,91 @@
|
||||
const MODULE_NAME = "token-decoder";
|
||||
|
||||
/*
|
||||
JSON Web Token (JWT) is a compact, URL-safe means of representing
|
||||
claims to be transferred between two parties. The claims in a JWT
|
||||
are encoded as a JSON object that is used as the payload of a JSON
|
||||
Web Signature (JWS) structure or as the plaintext of a JSON Web
|
||||
Encryption (JWE) structure, enabling the claims to be digitally
|
||||
signed or integrity protected with a Message Authentication Code
|
||||
(MAC) and/or encrypted.
|
||||
*/
|
||||
|
||||
const JSONWebToken = require('jsonwebtoken'); // A library to deal with JSON Web Tokens.
|
||||
const webTokenLibrary = require('jwks-rsa'); // A library to retrieve RSA signing keys from a JWKS (JSON Web Key Set) endpoint.
|
||||
|
||||
const AUTH_CONFIG = require('./Auth0'); // Config where we have our secrets.
|
||||
|
||||
const decoder = webTokenLibrary({
|
||||
cache: true,
|
||||
rateLimit: true,
|
||||
jwksRequestsPerMinute: 1,
|
||||
jwksUri: `https://${AUTH_CONFIG.domain}/.well-known/jwks.json`
|
||||
})
|
||||
|
||||
function decodeToken (token, callBackFunction) {
|
||||
|
||||
try{
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> decodeToken -> Entering function."); }
|
||||
|
||||
const decoded = JSONWebToken.decode(token, { complete: true });
|
||||
const header = decoded.header;
|
||||
const payload = decoded.payload;
|
||||
|
||||
if (
|
||||
header === null ||
|
||||
header.kid === null ||
|
||||
payload === null
|
||||
) {
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> Invalid Token. "); }
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> token = " + token); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
decoder.getSigningKey(header.kid, onKeyReady);
|
||||
|
||||
function onKeyReady(err, key) {
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> Entering function."); }
|
||||
|
||||
if (err) {
|
||||
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> Error getting the key. "); }
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> key = " + key); }
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> err = " + err); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
JSONWebToken.verify(
|
||||
token,
|
||||
key.publicKey,
|
||||
{ algorithms: ['RS256'] },
|
||||
onVerified);
|
||||
|
||||
function onVerified(err, decoded) {
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> Entering function."); }
|
||||
|
||||
if (err) {
|
||||
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> Error verifying. "); }
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> decoded = " + decoded); }
|
||||
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> err = " + err); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE, decoded);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> decodeToken -> err = " + err); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = decodeToken;
|
||||
@@ -0,0 +1,31 @@
|
||||
/* Debugging */
|
||||
|
||||
global.INFO_LOG = true;
|
||||
global.ERROR_LOG = true;
|
||||
|
||||
/* Callbacks default responses. */
|
||||
|
||||
global.DEFAULT_OK_RESPONSE = {
|
||||
result: "Ok",
|
||||
message: "Operation Succeeded"
|
||||
};
|
||||
|
||||
global.DEFAULT_FAIL_RESPONSE = {
|
||||
result: "Fail",
|
||||
message: "Operation Failed"
|
||||
};
|
||||
|
||||
global.DEFAULT_RETRY_RESPONSE = {
|
||||
result: "Retry",
|
||||
message: "Retry Later"
|
||||
};
|
||||
|
||||
global.CUSTOM_OK_RESPONSE = {
|
||||
result: "Ok, but check Message",
|
||||
message: "Custom Message"
|
||||
};
|
||||
|
||||
global.CUSTOM_FAIL_RESPONSE = {
|
||||
result: "Fail Because",
|
||||
message: "Custom Message"
|
||||
};
|
||||
+246
-43
@@ -1,8 +1,10 @@
|
||||
const MODULE_NAME = "schema";
|
||||
|
||||
const graphql = require('graphql');
|
||||
const _ = require('lodash');
|
||||
const User = require('../models/user');
|
||||
|
||||
const validateParseIdToken = require('../auth/validate-auth0-token');
|
||||
const tokenDecoder = require('../auth/token-decoder');
|
||||
|
||||
const {
|
||||
GraphQLObjectType,
|
||||
@@ -79,20 +81,32 @@ const RootQuery = new GraphQLObjectType({
|
||||
resolve(parent,args) {
|
||||
// Code to get data from data source.
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> RootQuery -> userByAuthId -> resolve -> Entering function."); }
|
||||
|
||||
User.findOne({authId: args.authId}, (err, user) => {
|
||||
if(err) reject(err);
|
||||
else{
|
||||
/* In order to be able to wait for asyc calls to the database, we need to return a promise to GraphQL. */
|
||||
|
||||
if (user.authId === args.authId && user.authId !== undefined) {
|
||||
return resolve(user);
|
||||
const promiseToGraphQL = new Promise((resolve, reject) => {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> RootQuery -> userByAuthId -> resolve -> Promise -> Entering function."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> RootQuery -> userByAuthId -> resolve -> Promise -> args.authId = " + args.authId); }
|
||||
|
||||
findUserByAuthId(args.authId, onUserFound);
|
||||
|
||||
function onUserFound(err, responseToGraphQL) {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> Entering function."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> responseToGraphQL = " + JSON.stringify(responseToGraphQL)); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> err.message = " + err.message); }
|
||||
reject (responseToGraphQL);
|
||||
} else {
|
||||
return null;
|
||||
resolve (responseToGraphQL);
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
return promiseToGraphQL;
|
||||
|
||||
}
|
||||
},
|
||||
@@ -125,45 +139,36 @@ const Mutation = new GraphQLObjectType({
|
||||
name: 'Mutation',
|
||||
fields: {
|
||||
authenticate: {
|
||||
type: UserType,
|
||||
args: {
|
||||
idToken: {type: new GraphQLNonNull(GraphQLString)}
|
||||
},
|
||||
resolve(parent, { idToken }) {
|
||||
let userToken = null;
|
||||
|
||||
return validateParseIdToken(idToken)
|
||||
.then(result => {
|
||||
console.log('validateParseIdToken', result);
|
||||
const authId = result.sub;
|
||||
const alias = result.nickname;
|
||||
|
||||
let user = new User({
|
||||
alias: alias,
|
||||
authId: authId,
|
||||
roleId: "1"
|
||||
});
|
||||
console.log(authId, alias);
|
||||
user.save();
|
||||
return { authId, alias };
|
||||
})
|
||||
.catch(err => { return {error: err } })
|
||||
}
|
||||
},
|
||||
addUser:{
|
||||
type: UserType,
|
||||
args: {
|
||||
alias: {type: new GraphQLNonNull(GraphQLString)},
|
||||
authId: {type: new GraphQLNonNull(GraphQLString)}
|
||||
idToken: {type: new GraphQLNonNull(GraphQLString)}
|
||||
},
|
||||
resolve(parent, args) {
|
||||
|
||||
let user = new User({
|
||||
alias: args.alias,
|
||||
authId: args.authId,
|
||||
roleId: "1"
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> Mutation -> authenticate -> resolve -> Entering function."); }
|
||||
|
||||
/* In order to be able to wait for asyc calls to the database, and authorization authority, we need to return a promise to GraphQL. */
|
||||
|
||||
const promiseToGraphQL = new Promise((resolve, reject) => {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> Mutation -> authenticate -> resolve -> Promise -> Entering function."); }
|
||||
authenticate(args.idToken, onAuthenticated);
|
||||
|
||||
function onAuthenticated(err, responseToGraphQL) {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> Entering function."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> responseToGraphQL = " + JSON.stringify(responseToGraphQL)); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> err.message = " + err.message); }
|
||||
reject (responseToGraphQL);
|
||||
} else {
|
||||
resolve (responseToGraphQL);
|
||||
}
|
||||
}
|
||||
});
|
||||
return user.save();
|
||||
|
||||
return promiseToGraphQL;
|
||||
}
|
||||
},
|
||||
updateUser:{
|
||||
@@ -204,6 +209,204 @@ const Mutation = new GraphQLObjectType({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function findUserByAuthId(authId, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> Entering function."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> authId = " + authId); }
|
||||
|
||||
if (authId === null || authId === undefined) {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> User requested not specified."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> args.authId = " + authId); }
|
||||
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: "Bad Request" });
|
||||
return;
|
||||
}
|
||||
|
||||
User.findOne({authId: authId}, onUserReceived)
|
||||
|
||||
function onUserReceived(err, user) {
|
||||
|
||||
if(err) {
|
||||
if (ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> Database Error."); }
|
||||
if (ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> err = " + err); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
}
|
||||
else{
|
||||
|
||||
if (user === null) {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> User not found at Database."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> args.authId = " + authId); }
|
||||
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_OK_RESPONSE.result,
|
||||
message: "User Not Found"
|
||||
};
|
||||
|
||||
callBackFunction(customResponse, { error: customResponse.message });
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.authId === authId && user.authId !== undefined) {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> User found at Database."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> args.authId = " + authId); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE, user);
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> User found at Database is not the user requested."); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> args.authId = " + authId); }
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> findUserByAuthId -> onUserReceived -> user.authId = " + user.authId); }
|
||||
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> findUserByAuthId -> err.message = " + err.message); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function authenticate(encodedToken, callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> Entering function."); }
|
||||
|
||||
let authId = "";
|
||||
let alias = "";
|
||||
let email = "";
|
||||
let emailVerified = false;
|
||||
|
||||
tokenDecoder(encodedToken, onValidated);
|
||||
|
||||
function onValidated(err, decodedToken) {
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> Entering function."); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> authenticate -> onValidated -> err.message = " + err.message); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Ok, the user was correctly authenticated. Next we need to know if this logged in user
|
||||
has already been added to this module's database or not yet.
|
||||
|
||||
*/
|
||||
|
||||
authId = decodedToken.sub;
|
||||
alias = decodedToken.nickname;
|
||||
email = decodedToken.email;
|
||||
emailVerified = decodedToken.email_verified;
|
||||
|
||||
findUserByAuthId(authId, onUserFound);
|
||||
|
||||
function onUserFound(err, user){
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> Entering function."); }
|
||||
|
||||
if (err.result === global.DEFAULT_FAIL_RESPONSE.result) {
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> err.message = " + err.message); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
return;
|
||||
}
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> User already exists at database"); }
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> Existing User: " + JSON.stringify(user)); }
|
||||
|
||||
/*
|
||||
|
||||
Here we save the user id of the logged in user at the server Sessions map, from there it will
|
||||
be used to validate any further transaction comming from this same user.
|
||||
|
||||
*/
|
||||
|
||||
global.Sessions.set(encodedToken, user.id);
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE, { authId: authId, alias: user.alias });
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
err.result === global.CUSTOM_OK_RESPONSE.result &&
|
||||
err.message === "User Not Found"
|
||||
) {
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> User does not exist at database"); }
|
||||
|
||||
/*
|
||||
|
||||
The authenticated user is NOT at our module database. We need to add him.
|
||||
We will take from the authentication provider the basic information it knows about the logged in users
|
||||
and save it as an initial set of data, which can later be modified.
|
||||
|
||||
*/
|
||||
|
||||
let newUser = new User({
|
||||
alias: alias,
|
||||
authId: authId,
|
||||
email: email,
|
||||
emailVerified: emailVerified,
|
||||
roleId: "1"
|
||||
});
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> " + alias + " being added to the database"); }
|
||||
|
||||
newUser.save(onSaved);
|
||||
|
||||
function onSaved(err, savedUser) {
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> onSaved -> Entering function."); }
|
||||
|
||||
if (err) {
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> onSaved -> err = " + err); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
return;
|
||||
}
|
||||
|
||||
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> authenticate -> onValidated -> onUserFound -> onSaved -> Saved User: " + JSON.stringify(savedUser)); }
|
||||
|
||||
/*
|
||||
|
||||
Here we save the user id of the logged in user at the server Sessions map, from there it will
|
||||
be used to validate any further transaction comming from this same user.
|
||||
|
||||
*/
|
||||
|
||||
global.Sessions.set(encodedToken, savedUser.id);
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE, { authId, alias });
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
|
||||
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> authenticate -> err.message = " + err.message); }
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err });
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new GraphQLSchema({
|
||||
query: RootQuery,
|
||||
mutation: Mutation
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
|
||||
Global in-memory Sessions
|
||||
|
||||
Here, we are going to store some information associated to the logged in user, after it was
|
||||
succesfully authenticated. This will prevent cheating, since we will use the in-Session
|
||||
user-id for any transaction belonging to the user instead of whatever user id it provides
|
||||
from the client app.
|
||||
|
||||
The key to access the in-Session information will allways be the authenticatioin token received
|
||||
at the authentication transaction. This token should always come at the header of each
|
||||
transactional functionality supported by this server module.
|
||||
|
||||
*/
|
||||
|
||||
global.Sessions = new Map();
|
||||
Reference in new issue
Block a user