From 7e35281bd196e328e1e050a8918c32e272f40c57 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 15 Feb 2022 14:30:26 -0800 Subject: [PATCH] createApp is no longer async, linting --- packages/api/src/apollo.ts | 3 +- packages/api/src/directives.ts | 40 +++++++++++ .../api/test/gql/sanitize-directive.test.ts | 69 +++++++++++++++++++ packages/api/test/util.ts | 6 ++ 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 packages/api/test/gql/sanitize-directive.test.ts diff --git a/packages/api/src/apollo.ts b/packages/api/src/apollo.ts index e52b91400..c39932f9c 100644 --- a/packages/api/src/apollo.ts +++ b/packages/api/src/apollo.ts @@ -20,7 +20,7 @@ import { makeExecutableSchema } from '@graphql-tools/schema' import { applyMiddleware } from 'graphql-middleware' import * as cookie from 'cookie' import typeDefs from './schema' -// import { SanitizeDirective } from './directives' +import { sanitizeDirectiveTransformer } from './directives' import { functionResolvers } from './resolvers/function_resolvers' import ScalarResolvers from './scalars' import * as Sentry from '@sentry/node' @@ -109,6 +109,7 @@ const contextFunc: ContextFunction = async ({ export function makeApolloServer(app: Express): ApolloServer { let schema = makeExecutableSchema({ typeDefs, resolvers }) + schema = sanitizeDirectiveTransformer(schema) const apollo = new ApolloServer({ schema: schema, context: contextFunc, diff --git a/packages/api/src/directives.ts b/packages/api/src/directives.ts index e3da60302..6885defd0 100644 --- a/packages/api/src/directives.ts +++ b/packages/api/src/directives.ts @@ -23,3 +23,43 @@ // } // } // } + +import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils' +import { GraphQLNonNull, GraphQLScalarType, GraphQLSchema } from 'graphql' +import { SanitizedString } from './scalars' + +export const sanitizeDirectiveTransformer = ( + schema: GraphQLSchema +): GraphQLSchema => { + return mapSchema(schema, { + [MapperKind.OBJECT_FIELD]: (fieldConfig) => { + const deprecatedDirective = getDirective( + schema, + fieldConfig, + 'sanitize' + )?.[0] + if (deprecatedDirective) { + // const { allowedTags, maxLength } = this.args + const allowedTags = undefined + const maxLength = undefined + if ( + fieldConfig.type instanceof GraphQLNonNull && + fieldConfig.type.ofType instanceof GraphQLScalarType + ) { + fieldConfig.type = new GraphQLNonNull( + new SanitizedString(fieldConfig.type.ofType, allowedTags, maxLength) + ) + } else if (fieldConfig.type instanceof GraphQLScalarType) { + fieldConfig.type = new SanitizedString( + fieldConfig.type, + allowedTags, + maxLength + ) + } else { + throw new Error(`Not a scalar type: ${fieldConfig.type}`) + } + } + return fieldConfig + }, + }) +} diff --git a/packages/api/test/gql/sanitize-directive.test.ts b/packages/api/test/gql/sanitize-directive.test.ts new file mode 100644 index 000000000..c52842d50 --- /dev/null +++ b/packages/api/test/gql/sanitize-directive.test.ts @@ -0,0 +1,69 @@ +// import { createTestUser, deleteTestUser, getProfile, getUser } from '../db' +// import { graphqlRequest, request } from '../util' +// import { expect } from 'chai' +// import { +// LoginErrorCode, +// SignupErrorCode, +// UpdateUserErrorCode, +// UpdateUserProfileErrorCode, +// } from '../../src/generated/graphql' +// import { User } from '../../src/entity/user' +// import { hashPassword } from '../../src/utils/auth' +// import 'mocha' + +// describe('Sanitize Directive', () => { +// const username = 'fake_user' +// const correctPassword = 'fakePassword' + +// let authToken: string +// let user: User + +// before(async () => { +// const hashedPassword = hashPassword(correctPassword) +// user = await createTestUser(username, '', hashedPassword) +// const res = await request +// .post('/local/debug/fake-user-login') +// .send({ fakeEmail: user.email }) + +// authToken = res.body.authToken +// }) + +// after(async () => { +// await deleteTestUser(username) +// }) + +// describe('Update user with a bio that is too long', () => { +// let bio = "".padStart(500, '*'); +// let query: string + +// beforeEach(() => { +// query = ` +// mutation { +// updateUser( +// input: { +// name: "fakeUser" +// bio: "${bio}" +// } +// ) { +// ... on UpdateUserSuccess { +// user { +// id +// } +// } +// ... on UpdateUserError { +// errorCodes +// } +// } +// } +// ` +// }) + +// it('responds with error code EMPTY_NAME', async () => { +// const response = await graphqlRequest(query, authToken) +// console.log('GOT RESPONSE', response) +// expect(response.body.data.updateUser.errorCodes).to.eql([ +// UpdateUserErrorCode.EmptyName, +// ]) +// }) +// }) +// }) diff --git a/packages/api/test/util.ts b/packages/api/test/util.ts index 05b408814..d9e72fa87 100644 --- a/packages/api/test/util.ts +++ b/packages/api/test/util.ts @@ -1,10 +1,16 @@ import { createApp } from '../src/server' import supertest from 'supertest' import { v4 } from 'uuid' +import { corsConfig } from '../src/utils/corsConfig' const { app, apollo } = createApp() export const request = supertest(app) +before(async () => { + await apollo.start() + apollo.applyMiddleware({ app, path: '/api/graphql', cors: corsConfig }) +}) + export const graphqlRequest = ( query: string, authToken?: string