Skip to content

Commit 15c1e88

Browse files
authored
feat(wabe): block graphql introspection in production (#264)
1 parent ed6527f commit 15c1e88

File tree

5 files changed

+91
-27
lines changed

5 files changed

+91
-27
lines changed

bun.lock

Lines changed: 13 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/wabe/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
"generate:codegen": "touch generated/wabe.ts && CODEGEN=true bun dev/index.ts"
3030
},
3131
"dependencies": {
32-
"@graphql-yoga/plugin-disable-introspection": "2.10.9",
3332
"croner": "9.0.0",
3433
"graphql": "16.12.0",
3534
"js-srp6a": "1.0.2",

packages/wabe/src/security.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,49 @@ describe('Security tests', () => {
2222
await wabe.close()
2323
})
2424

25+
it('should block GraphQL introspection queries for anonymous and authenticated users for isProduction server', async () => {
26+
const setup = await setupTests([], true)
27+
wabe = setup.wabe
28+
port = setup.port
29+
client = getAnonymousClient(port)
30+
rootClient = getGraphqlClient(port)
31+
32+
// Test pour un utilisateur anonyme
33+
expect(
34+
client.request(gql`
35+
query IntrospectionQuery {
36+
__schema {
37+
types {
38+
name
39+
}
40+
}
41+
}
42+
`),
43+
).rejects.toThrow('GraphQL introspection is not allowed in production')
44+
45+
// Test pour un utilisateur authentifié (même un admin)
46+
const { userClient } = await createUserAndUpdateRole({
47+
anonymousClient: client,
48+
port,
49+
roleName: 'Admin',
50+
rootClient,
51+
})
52+
53+
expect(
54+
userClient.request(gql`
55+
query IntrospectionQuery {
56+
__schema {
57+
types {
58+
name
59+
}
60+
}
61+
}
62+
`),
63+
).rejects.toThrow('GraphQL introspection is not allowed in production')
64+
65+
await closeTests(wabe)
66+
})
67+
2568
it('should return null if the accessToken is an invalid accessToken', async () => {
2669
const setup = await setupTests()
2770
wabe = setup.wabe

packages/wabe/src/server/index.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
Schema,
66
type SchemaInterface,
77
} from '../schema/Schema'
8-
import { GraphQLObjectType, GraphQLSchema } from 'graphql'
8+
import { GraphQLError, GraphQLObjectType, GraphQLSchema } from 'graphql'
99
import { GraphQLSchema as WabeGraphQLSchema } from '../graphql'
1010
import type { AuthenticationConfig } from '../authentication/interface'
1111
import { type WabeRoute, defaultRoutes } from './routes'
@@ -23,7 +23,6 @@ import { defaultSessionHandler } from './defaultHandlers'
2323
import type { CronConfig } from '../cron'
2424
import type { FileConfig } from '../file'
2525
import { WobeGraphqlYogaPlugin } from 'wobe-graphql-yoga'
26-
import { useDisableIntrospection } from '@graphql-yoga/plugin-disable-introspection'
2726

2827
type SecurityConfig = {
2928
corsOptions?: CorsOptions
@@ -285,7 +284,38 @@ export class Wabe<T extends WabeTypes> {
285284
this.config.security?.hideSensitiveErrorMessage ||
286285
this.config.isProduction,
287286
graphqlEndpoint: '/graphql',
288-
plugins: this.config.isProduction ? [useDisableIntrospection()] : [],
287+
plugins: [
288+
{
289+
// @ts-expect-error
290+
onValidate: ({ addValidationRule }) => {
291+
// @ts-expect-error
292+
addValidationRule((context) => {
293+
return {
294+
// @ts-expect-error
295+
Field(node) {
296+
const introspectionFields = [
297+
'__schema',
298+
'__type',
299+
'__typeKind',
300+
'__field',
301+
'__inputValue',
302+
'__enumValue',
303+
'__directive',
304+
]
305+
306+
if (introspectionFields.includes(node.name.value)) {
307+
context.reportError(
308+
new GraphQLError(
309+
'GraphQL introspection is not allowed in production',
310+
),
311+
)
312+
}
313+
},
314+
}
315+
})
316+
},
317+
},
318+
],
289319
context: async (ctx): Promise<WabeContext<T>> => ctx.wabe,
290320
}),
291321
)

packages/wabe/src/utils/testHelper.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ export const getDatabaseAdapter = async (databaseName: string) => {
1717

1818
export const setupTests = async (
1919
additionalClasses: ClassInterface<any>[] = [],
20+
isProduction = false,
2021
) => {
2122
const databaseId = uuid()
2223

2324
const port = await getPort()
2425

2526
const wabe = new Wabe<DevWabeTypes>({
26-
isProduction: false,
27+
isProduction,
2728
rootKey: 'dev',
2829
database: {
2930
// @ts-expect-error

0 commit comments

Comments
 (0)