diff --git a/api/package-lock.json b/api/package-lock.json index 7875d82ce..d5e74e85c 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -1618,7 +1618,7 @@ }, "apollo-link-error": { "version": "1.0.9", - "resolved": "http://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.0.9.tgz", + "resolved": "https://registry.npmjs.org/apollo-link-error/-/apollo-link-error-1.0.9.tgz", "integrity": "sha512-82qgIH0UC039kcvcFDJkY8GuUOgPFrkYe/0zNFkA0AXvuvL4RHxWb8SWRiPwtP8jKaKEOedyjopfyH84aLiu7Q==", "requires": { "apollo-link": "^1.2.2" @@ -1626,7 +1626,7 @@ }, "apollo-link-ws": { "version": "1.0.8", - "resolved": "http://registry.npmjs.org/apollo-link-ws/-/apollo-link-ws-1.0.8.tgz", + "resolved": "https://registry.npmjs.org/apollo-link-ws/-/apollo-link-ws-1.0.8.tgz", "integrity": "sha512-ucuGvr8CBBwCHl/Rbtyuv9Fn0FN5Qoyvy84KHtuMl2Uux2Sq+jt3bUum+pZ+hZntEd9k8M1OjrrXqRJ4PtEpyA==", "requires": { "apollo-link": "^1.2.2" @@ -2042,7 +2042,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "optional": true, "requires": { "tweetnacl": "^0.14.3" } @@ -3317,7 +3316,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "optional": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -6065,8 +6063,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "jsesc": { "version": "2.5.1", @@ -7888,7 +7885,7 @@ }, "jsonwebtoken": { "version": "8.2.1", - "resolved": "http://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.2.1.tgz", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.2.1.tgz", "integrity": "sha512-l8rUBr0fqYYwPc8/ZGrue7GiW7vWdZtZqelxo4Sd5lMvuEeCK8/wS54sEo6tJhdZ6hqfutsj6COgC0d1XdbHGw==", "requires": { "jws": "^3.1.4", @@ -9015,11 +9012,20 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", - "dev": true, "requires": { "lodash": "^4.13.1" } }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9640,9 +9646,9 @@ "dev": true }, "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz", + "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==", "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -9687,8 +9693,7 @@ "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" }, "stream-combiner": { "version": "0.2.2", @@ -10171,8 +10176,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-is": { "version": "1.6.16", diff --git a/api/package.json b/api/package.json index 6e4a74f8c..057991f3d 100644 --- a/api/package.json +++ b/api/package.json @@ -32,6 +32,8 @@ "lodash.get": "^4.4.2", "nodemon": "^1.18.4", "prisma-binding": "^2.1.6", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", "winston": "^3.1.0" }, "devDependencies": { diff --git a/api/src/auth/authDirectives.js b/api/src/auth/authDirectives.js deleted file mode 100644 index e13b33532..000000000 --- a/api/src/auth/authDirectives.js +++ /dev/null @@ -1,144 +0,0 @@ -const _get = require('lodash.get') -const { validateIdToken } = require('./validateIdToken') - -const memberLocationOnContext = 'request.user' -const bearerAccessToken = 'request.headers.authorization' - -const ctxMember = ctx => _get(ctx, memberLocationOnContext) -const ctxToken = ctx => _get(ctx, bearerAccessToken) - -const createMember = async (ctx, idToken, info) => { - console.log('createMember', idToken) - const member = await ctx.db.mutation.upsertMember({ - where: { - authId: idToken.sub, - }, - create: { - authId: idToken.sub, - alias: idToken.nickname - }, - update: { - authId: idToken.sub, - alias: idToken.nickname - } - }, info) - return member -} - -const isLoggedIn = async ctx => { - console.log('isLoggedIn 0 : ', ctx.request.headers) - let member = ctxMember(ctx, memberLocationOnContext) - let token = ctxToken(ctx, bearerAccessToken) - let memberToken - console.log('isLoggedIn: ', member, token) - if (!member && 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 - // console.log('isLoggedIn2 : ', token) - try { - memberToken = await validateIdToken(token) - const authId = memberToken.sub - // console.log('isLoggedIn3 : ', await authId, ctx.db.query.member) - exists = await ctx.db.query.member({ where: { authId: authId } }) - // console.log('isLoggedIn4 : ', await exists, createMember ) - if (!member && exists === null) { - member = await createMember(ctx, memberToken).then(res => { - // console.log('isLoggedIn5 : ', res) - return res - }) - - return member - } - return member - } catch (err) { - memberToken = false - } - } - } - // console.log('isLoggedIn5 : ', await member) - if (!member) { - throw new Error(`Not logged in`) - } - return member -} - - -const isRequestingMemberAlsoOwner = ({ ctx, memberId, type, typeId }) => - ctx.db.exists[type]({ slug: typeId, owner: memberId }) -const isRequestingMember = ({ ctx, memberId }) => ctx.db.exists.Member({ authId: memberId }) - -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`) - }, - isOwner: async (next, source, { type }, ctx) => { - console.log('directive isOwner: ', source, type, ctx) - const { slug: typeId } = - source && source.id - ? source - : ctx.request.body.variables ? ctx.request.body.variables : { id: null } - const user = await isLoggedIn(ctx) - // console.log('directive isOwner 0: ', typeId, user.sub) - const memberId = user.sub - const isOwner = - type === `Member` - ? memberId === typeId - : await isRequestingMemberAlsoOwner({ ctx, memberId, type, typeId }) - // console.log('directive isOwner 1: ', source, isOwner, type, typeId, memberId) - if (isOwner) { - return next() - } - throw new Error(`Unauthorized, must be owner`) - }, - isOwnerOrHasRole: async (next, source, { roles, type }, ctx, ...p) => { - const { authId: memberId } = await isLoggedIn(ctx) - console.log('directive isOwnerOrHasRole 1: ', memberId, roles, type) - if(memberId === undefined && role=== undefined) throw new Error(`Not logged in`) - if (roles.includes(role)) { - return next() - } - - const { authId: typeId } = ctx.request.body.variables - const isOwner = await isRequestingMemberAlsoOwner({ - ctx, - memberId, - type, - typeId - }) - console.log('directive isOwnerOrHasRole 2: ', typeId, memberId, role, isOwner) - if (isOwner) { - return next() - } - - const hasRole = await isRequestingMember({ - ctx, - memberId, - type, - typeId - }) - if(hasRole){ - return next() - } - throw new Error(`Unauthorized, not owner or incorrect role`) - } -} - -module.exports = { directiveResolvers } diff --git a/api/src/directives/index.js b/api/src/directives/index.js index eca156df1..8e6b925ae 100644 --- a/api/src/directives/index.js +++ b/api/src/directives/index.js @@ -12,7 +12,7 @@ const ctxMember = ctx => _get(ctx, memberLocationOnContext) const ctxToken = ctx => _get(ctx, bearerAccessToken) const createMember = async (ctx, idToken, info) => { - logger.info('createMember', idToken) + logger.info(`createMember: ${idToken}`) const member = await ctx.db.mutation.upsertMember({ where: { authId: idToken.sub, @@ -30,7 +30,7 @@ const createMember = async (ctx, idToken, info) => { } const isLoggedIn = async ctx => { - logger.info('isLoggedIn 0 : ', ctx.request.headers) + logger.info(`isLoggedIn 0: ${JSON.stringify(ctx.request.headers)}`) let member = ctxMember(ctx, memberLocationOnContext) let token = ctxToken(ctx, bearerAccessToken) let memberToken @@ -46,16 +46,12 @@ const isLoggedIn = async ctx => { if (/^Bearer$/i.test(scheme)) { token = credentials //verify token - // console.log('isLoggedIn2 : ', token) try { memberToken = await validateIdToken(token) const authId = memberToken.sub - // console.log('isLoggedIn3 : ', await authId, ctx.db.query.member) exists = await ctx.db.query.member({ where: { authId: authId } }) - // console.log('isLoggedIn4 : ', await exists, createMember ) if (!member && exists === null) { member = await createMember(ctx, memberToken).then(res => { - // console.log('isLoggedIn5 : ', res) return res }) @@ -67,7 +63,6 @@ const isLoggedIn = async ctx => { } } } - // console.log('isLoggedIn5 : ', await member) if (!member) { throw new AuthenticationError('Access token is missing or expired') } @@ -113,13 +108,11 @@ export const directiveResolvers = { ? source : ctx.request.body.variables ? ctx.request.body.variables : { id: null } const user = await isLoggedIn(ctx) - // console.log('directive isOwner 0: ', typeId, user.sub) const memberId = user.sub const isOwner = type === `Member` ? memberId === typeId : await isRequestingMemberAlsoOwner({ ctx, memberId, type, typeId }) - // console.log('directive isOwner 1: ', source, isOwner, type, typeId, memberId) if (isOwner) { return next() } diff --git a/api/src/email/sendgrid.js b/api/src/email/sendgrid.js index b3b7d5264..e5243a357 100644 --- a/api/src/email/sendgrid.js +++ b/api/src/email/sendgrid.js @@ -1,9 +1,11 @@ var jwt = require('jsonwebtoken') var axios = require('axios') +import { logger } from '../logger' + const sendTeamMemberInvite = function(email, team) { const dev = process.env.NODE_ENV === 'development' ? true : false - console.log('sendTeamMemberInvite', email, team) + logger.info(`sendTeamMemberInvite email|team: ${email} | ${team}`) const API_KEY = process.env.SG_APIKEY const token = jwt.sign({ email: email, team: team.slug }, API_KEY, { expiresIn: '7d' }) let origin = 'https://teams.advancedalgos.net' @@ -69,7 +71,7 @@ const sendTeamMemberInvite = function(email, team) { const sendTeamCreateConfirmation = function(email, teamName, botName) { const dev = process.env.NODE_ENV === 'development' ? true : false - console.log('sendTeamMemberInvite', email, teamName, botName) + logger.info(`sendTeamCreateConfirmation email|teamName|botName: ${email} | ${teamName} | ${botName}`) const API_KEY = process.env.SG_APIKEY let origin = 'https://teams.advancedalgos.net' if (dev){ @@ -144,8 +146,7 @@ const verifyInviteToken = async function(token) { throw new Error (`Error: Token error - ${err.message}`) } } - - console.log('verifyInviteToken', verifiedToken) + logger.info(`verifyInviteToken: ${verifiedToken}`) return verifiedToken } diff --git a/api/src/index.js b/api/src/index.js index 0487e9b85..43efb44cb 100644 --- a/api/src/index.js +++ b/api/src/index.js @@ -155,55 +155,57 @@ const resolvers = { return team }, async createTeam(parent, { name, slug, botName, botSlug }, ctx, info) { - console.log('createTeam ctx:', ctx.request.user) + logger.info(ctx.request.user, 'createTeam ctx.request.user:') const authId = ctx.request.user.sub + const encodedAuthId = encodeURI(authId) - const encodedURL = `https://users-api.advancedalgos.net/graphql?query=%7B%0A%20%20userByAuthId(authId%3A%20"${encodedAuthId}")%7B%0A%20%20%20%20id%0A%09%09email%0A%20%20%20%20alias%0A%20%20%7D%0A%7D` + const encodedURL = `https://users-api.advancedalgos.net/graphql?query=%7B%0A%20%20userByAuthId(authId:%20%22${authId}%22)%20%7B%0A%20%20%20%20id%0A%20%20%20%20email%0A%20%20%20%20alias%0A%20%20%7D%0A%7D%0A` const decodedURL = decodeURI(encodedURL) - logger.info('createTeam URLs: ', encodedURL, decodedURL) - const getUserModuleUser = await axios.get(encodedURL) - .then((result) => { - logger.info('getUserModuleUser axios:', result) - return result - }) - .catch(err =>{ - logger.debug('getUserModuleUser err:', err) - }) + return getUser(authId) + .then(async result => { + logger.info('axios:') + logger.info(result) - logger.info('getUserModuleUser:', await getUserModuleUser) - const alias = await getUserModuleUser.data.data.userByAuthId.alias - const email = getUserModuleUser.data.data.userByAuthId.email - const avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png' - const banner = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-banner-default.png' + const alias = result.data.users_UserByAuthId.alias + const email = result.data.users_UserByAuthId.email + const avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png' + const banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png' - const createTeamUrl = encodeURI(`${slug}/${name}/${alias}/${botSlug}/${authId}`) - const platformUrl = 'https://develop.advancedalgos.net/AABrowserAPI/teamSetup/' - // const platformUrl = 'http://localhost:3100/AABrowserAPI/teamSetup/' - const createPlatformTeam = await axios.get(`${platformUrl}${createTeamUrl}`) - .then((result) => { - logger.info('createPlatformTeam:', result) - if(result.data.message === 'Team Name already taken'){ - throw new Error(result.data.message) + const createTeamUrl = encodeURI(`${slug}/${name}/${alias}/${botSlug}/${authId}`) + logger.info('createTeamUrl:') + logger.info(JSON.stringify(await createTeamUrl)) + + const platformUrl = 'https://develop.advancedalgos.net/AABrowserAPI/teamSetup/' + // const platformUrl = 'http://localhost:3100/AABrowserAPI/teamSetup/' + const createPlatformTeam = await axios.get(`${platformUrl}${createTeamUrl}`) + .then((result) => { + logger.info('createPlatformTeam:', result) + if(result.data.message === 'Team Name already taken'){ + throw new Error(result.data.message) + } + return result + }) + .catch(err =>{ + logger.errror('createPlatformTeam err:', err) + throw new Error(err) + }) + logger.info('createPlatformTeam: ', await createPlatformTeam) + if(createPlatformTeam === 'Error: Team Name already taken'){ + return createPlatformTeam } - return result + const createTeam = await ctx.db.mutation.createTeam({ data: {name: name, slug: slug, owner: authId, members: {create: {member: {create: {authId: authId, alias: alias, visible:'true', status: { create: { status: 'ACTIVE', reason: `Created team ${name}`}}}}, role: 'OWNER'}}, profile: {create: {avatar: avatar, banner: banner}}, fb: {create: {name: botName, slug: botSlug, kind:'TRADER', avatar: avatar, status: {create: {status: 'ACTIVE', reason: "Cloned on team creation"}}}}, status: {create: {status: 'ACTIVE', reason:"Team created"}}} }, TEAMS_FRAGMENT) + .catch((err) => { + logger.debug(err, 'createTeam error: ') + return err + }) + + sendTeamCreateConfirmation(email, name, botName) + return createTeam }) - .catch(err =>{ - logger.errror('createPlatformTeam err:', err) - throw new Error(err) - }) - logger.info('createPlatformTeam: ', await createPlatformTeam) - if(createPlatformTeam === 'Error: Team Name already taken'){ - return createPlatformTeam - } - const createTeam = await ctx.db.mutation.createTeam({ data: {name: name, slug: slug, owner: authId, members: {create: {member: {connect: {authId: authId}}, role: 'OWNER'}}, profile: {create: {avatar: avatar, banner: banner}}, fb: {create: {name: botName, slug: botSlug, kind:'TRADER', avatar: avatar, status: {create: {status: 'ACTIVE', reason: "Cloned on team creation"}}}}, status: {create: {status: 'ACTIVE', reason:"Team created"}}} }, TEAMS_FRAGMENT) .catch((err) => { - logger.debug('createTeam error: ', err) + logger.debug('createTeam error: ') return err }) - - sendTeamCreateConfirmation(email, name, botName) - - return createTeam }, async updateTeamProfile(parent, { slug, owner, description, motto, avatar, banner }, ctx, info) { return ctx.db.mutation.updateTeam({data:{profile: {update: {description: description, motto: motto, avatar: avatar, banner: banner}}}, where:{slug: slug}}, TEAMS_FRAGMENT) @@ -231,6 +233,45 @@ const resolvers = { } } +const getUser = authId => { + logger.info('getUser') + logger.info(authId) + const API_URL = 'https://app-api.advancedalgos.net/graphql' + return new Promise(resolve => { + try { + const result = axios.post(API_URL, { + query: `query users_UserByAuthId($authId: String!) { + users_UserByAuthId(authId: $authId){ + id + alias + email + } + }`, + variables: { + authId: authId + } + }, { + headers: { + 'Content-Type': 'application/json' + } + }) + .then(result => { + logger.info('getUser result') + logger.info(result.data) + resolve(result.data) + }) + .catch(err => { + logger.info('getUser err') + logger.info(err) + throw new Error(err) + }) + + } catch (error) { + resolve(error) + } + }) +} + const db = new Prisma({ fragmentReplacements: extractFragmentReplacements(resolvers), typeDefs: 'src/generated/prisma.graphql', diff --git a/api/src/logger/index.js b/api/src/logger/index.js index d21029370..7d55674e9 100644 --- a/api/src/logger/index.js +++ b/api/src/logger/index.js @@ -6,9 +6,9 @@ class LoggerService { new transports.Console({ format: format.combine( format.colorize(), - format.timestamp({ format: 'YYYY/MM/DD HH:mm' }), + format.timestamp({ format: 'YY/MM/DD HH:mm' }), format.printf( - info => `${info.timestamp} - ${info.level}: ${info.message}` + info => `${info.timestamp} - ${info.level}: ${JSON.stringify(info.message)}` ) ), }), diff --git a/client/src/views/financial-beings/components/ManageFBEdit.js b/client/src/views/financial-beings/components/ManageFBEdit.js index 323aec53d..6619b342f 100644 --- a/client/src/views/financial-beings/components/ManageFBEdit.js +++ b/client/src/views/financial-beings/components/ManageFBEdit.js @@ -68,7 +68,7 @@ export class ManageFBEdit extends Component { const containerName = slug let avatar = null - if (this.state.avatar === null && fb.avatar === undefined) avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png' + if (this.state.avatar === null && fb.avatar === undefined) avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png' if (fb.avatar !== undefined && fb.avatar !== null) avatar = fb.avatar if (this.state.avatar !== null) avatar = this.state.avatar diff --git a/client/src/views/manage-teams/components/ManageTeamEdit.js b/client/src/views/manage-teams/components/ManageTeamEdit.js index 4ececf5f0..46faafbd6 100644 --- a/client/src/views/manage-teams/components/ManageTeamEdit.js +++ b/client/src/views/manage-teams/components/ManageTeamEdit.js @@ -76,12 +76,12 @@ export class ManageTeamEdit extends Component { const AzureStorageSAS = process.env.AZURE_STORAGE_SAS_TEAMS const containerName = team.slug let avatar = null - if (this.state.avatar === null && team.profile !== null && (team.profile.avatar === undefined || team.profile.avatar === null)) avatar = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-avatar-default.png' + if (this.state.avatar === null && team.profile !== null && (team.profile.avatar === undefined || team.profile.avatar === null)) avatar = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-avatar-default.png' if (team.profile !== null && team.profile.avatar !== undefined && team.profile.avatar !== null) avatar = team.profile.avatar if (this.state.avatar !== null) avatar = this.state.avatar let banner = null - if (this.state.banner === null && team.profile !== null && (team.profile.banner === undefined || team.profile.banner === null)) banner = 'https://algobotcommstorage.blob.core.windows.net/aateammodule/aa-banner-default.png' + if (this.state.banner === null && team.profile !== null && (team.profile.banner === undefined || team.profile.banner === null)) banner = 'https://aadevelop.blob.core.windows.net/module-teams/module-default/aa-banner-default.png' if (team.profile !== null && team.profile.banner !== undefined && team.profile.banner !== null) banner = team.profile.banner if (this.state.banner !== null) banner = this.state.banner console.log('team images: ', avatar, banner)