Implement the sanitize directive in applo 3.0

This commit is contained in:
Jackson Harper
2022-02-15 15:33:31 -08:00
parent 7e35281bd1
commit 6d5554dd5f
4 changed files with 1037 additions and 1095 deletions

View File

@ -108,8 +108,13 @@ const contextFunc: ContextFunction<ExpressContext, ResolverContext> = async ({
}
export function makeApolloServer(app: Express): ApolloServer {
let schema = makeExecutableSchema({ typeDefs, resolvers })
let schema = makeExecutableSchema({
resolvers,
typeDefs
})
schema = sanitizeDirectiveTransformer(schema)
const apollo = new ApolloServer({
schema: schema,
context: contextFunc,

View File

@ -1,63 +1,30 @@
/* eslint-disable @typescript-eslint/restrict-template-expressions */
// import { SchemaDirectiveVisitor } from 'apollo-server-express'
// import { GraphQLInputField, GraphQLScalarType } from 'graphql'
// import { SanitizedString } from './scalars'
// import { GraphQLNonNull } from 'graphql/type/definition'
// export class SanitizeDirective extends SchemaDirectiveVisitor {
// visitInputFieldDefinition(
// field: GraphQLInputField
// ): GraphQLInputField | void | null {
// const { allowedTags, maxLength } = this.args
// if (
// field.type instanceof GraphQLNonNull &&
// field.type.ofType instanceof GraphQLScalarType
// ) {
// field.type = new GraphQLNonNull(
// new SanitizedString(field.type.ofType, allowedTags, maxLength)
// )
// } else if (field.type instanceof GraphQLScalarType) {
// field.type = new SanitizedString(field.type, allowedTags, maxLength)
// } else {
// throw new Error(`Not a scalar type: ${field.type}`)
// }
// }
// }
import { mapSchema, getDirective, MapperKind } from '@graphql-tools/utils'
import { GraphQLNonNull, GraphQLScalarType, GraphQLSchema } from 'graphql'
import { SanitizedString } from './scalars'
export const sanitizeDirectiveTransformer = (
schema: GraphQLSchema
): GraphQLSchema => {
export const sanitizeDirectiveTransformer = (schema: GraphQLSchema) => {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const deprecatedDirective = getDirective(
[MapperKind.FIELD]: (fieldConfig) => {
const sanitizeDirective = 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}`)
}
)
if (!sanitizeDirective || sanitizeDirective.length < 1) {
return fieldConfig
}
const maxLength = sanitizeDirective[0].maxLength
const allowedTags = sanitizeDirective[0].allowedTags
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
},

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +1,65 @@
// 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'
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'
describe('Sanitize Directive', () => {
const username = 'fake_user'
const correctPassword = 'fakePassword'
// let authToken: string
// let user: User
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 })
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
// })
authToken = res.body.authToken
})
// after(async () => {
// await deleteTestUser(username)
// })
after(async () => {
await deleteTestUser(username)
})
// describe('Update user with a bio that is too long', () => {
// let bio = "".padStart(500, '*');
// let query: string
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
// }
// }
// }
// `
// })
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,
// ])
// })
// })
// })
it('responds with error code EMPTY_NAME', async () => {
expect(async () => { await graphqlRequest(query, authToken) }).to.throw
})
})
})