This commit is contained in:
Barry Low committed 2018-09-10 20:24:11 -07:00
commit 0669921d0e
24 files changed
+465 -300

No files matched your search

+2 -2
View File
@@ -20,9 +20,9 @@ App.js
| | |
| | |- UserTabs
| | | |
| | | |- Tab 1 - AddUser
| | | |- Tab 1 - UserUpdate
| | | |
| | | |- Tab 2 - UpdateUser
| | | |- Tab 2 - ManageImages
| |
| |- Browse
| | |
+1 -1
View File
@@ -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 -3
View File
@@ -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>
)
-53
View File
@@ -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.
-1
View File
@@ -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>
-20
View File
@@ -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>
+1 -5
View File
@@ -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>
);
+6 -1
View File
@@ -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 }) => {
+3 -1
View File
@@ -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='/' />
}
+11 -14
View File
@@ -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 });
}
}
+14
View File
@@ -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
+5 -17
View File
@@ -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.
-17
View File
@@ -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
-7
View File
@@ -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

-15
View File
@@ -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
View File
@@ -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');
});
-69
View File
@@ -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 }
+91
View File
@@ -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;
+31
View File
@@ -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
View File
@@ -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
+16
View File
@@ -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();