Skip to content

Commit

Permalink
Merge pull request #446 from AikidoSec/discover-graphql-schema
Browse files Browse the repository at this point in the history
Discover GraphQL schema when execute is called
  • Loading branch information
willem-delbare authored Nov 8, 2024
2 parents 65f83c0 + 0e45307 commit 2871bb6
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 15 deletions.
8 changes: 8 additions & 0 deletions library/agent/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,14 @@ export class Agent {
this.routes.addRoute(context);
}

hasGraphQLSchema(method: string, path: string) {
return this.routes.hasGraphQLSchema(method, path);
}

onGraphQLSchema(method: string, path: string, schema: string) {
this.routes.setGraphQLSchema(method, path, schema);
}

onGraphQLExecute(
method: string,
path: string,
Expand Down
39 changes: 39 additions & 0 deletions library/agent/Routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ t.test("it works", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -53,6 +54,7 @@ t.test("it works", async (t) => {
hits: 2,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -66,13 +68,15 @@ t.test("it works", async (t) => {
hits: 2,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
path: "/users",
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
],
"Should add second route"
Expand All @@ -86,20 +90,23 @@ t.test("it works", async (t) => {
hits: 2,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
path: "/users",
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "PUT",
path: "/users/1",
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -111,20 +118,23 @@ t.test("it works", async (t) => {
hits: 2,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "PUT",
path: "/users/1",
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "DELETE",
path: "/users/1",
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -143,13 +153,15 @@ t.test("it adds GraphQL fields", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
path: "/graphql",
hits: 1,
graphql: { type: "query", name: "user" },
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -161,13 +173,15 @@ t.test("it adds GraphQL fields", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
path: "/graphql",
hits: 2,
graphql: { type: "query", name: "user" },
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -179,13 +193,15 @@ t.test("it adds GraphQL fields", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
path: "/graphql",
hits: 2,
graphql: { type: "query", name: "user" },
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
Expand All @@ -196,6 +212,7 @@ t.test("it adds GraphQL fields", async (t) => {
name: "post",
},
apispec: {},
graphQLSchema: undefined,
},
]);

Expand All @@ -207,13 +224,15 @@ t.test("it adds GraphQL fields", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
path: "/graphql",
hits: 2,
graphql: { type: "query", name: "user" },
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
Expand All @@ -224,6 +243,7 @@ t.test("it adds GraphQL fields", async (t) => {
name: "post",
},
apispec: {},
graphQLSchema: undefined,
},
{
method: "POST",
Expand All @@ -234,6 +254,7 @@ t.test("it adds GraphQL fields", async (t) => {
name: "post",
},
apispec: {},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -284,6 +305,7 @@ t.test("it adds body schema", async (t) => {
query: undefined,
auth: undefined,
},
graphQLSchema: undefined,
},
]);
});
Expand All @@ -299,6 +321,7 @@ t.test("it merges body schema", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);

Expand Down Expand Up @@ -344,6 +367,7 @@ t.test("it merges body schema", async (t) => {
},
auth: undefined,
},
graphQLSchema: undefined,
},
]);

Expand Down Expand Up @@ -399,6 +423,7 @@ t.test("it merges body schema", async (t) => {
},
auth: undefined,
},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -430,6 +455,7 @@ t.test("it adds query schema", async (t) => {
},
},
},
graphQLSchema: undefined,
},
]);
});
Expand All @@ -445,6 +471,7 @@ t.test("it merges query schema", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);
routes.addRoute(getContext("GET", "/query", {}, undefined, { test: "abc" }));
Expand Down Expand Up @@ -473,6 +500,7 @@ t.test("it merges query schema", async (t) => {
},
auth: undefined,
},
graphQLSchema: undefined,
},
]);
});
Expand All @@ -499,6 +527,7 @@ t.test("it adds auth schema", async (t) => {
query: undefined,
auth: [{ type: "http", scheme: "bearer" }],
},
graphQLSchema: undefined,
},
{
method: "GET",
Expand All @@ -510,6 +539,7 @@ t.test("it adds auth schema", async (t) => {
query: undefined,
auth: [{ type: "apiKey", in: "cookie", name: "session" }],
},
graphQLSchema: undefined,
},
{
method: "GET",
Expand All @@ -521,6 +551,7 @@ t.test("it adds auth schema", async (t) => {
query: undefined,
auth: [{ type: "apiKey", in: "header", name: "x-api-key" }],
},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -549,6 +580,7 @@ t.test("it merges auth schema", async (t) => {
{ type: "apiKey", in: "header", name: "x-api-key" },
],
},
graphQLSchema: undefined,
},
]);
});
Expand All @@ -563,6 +595,7 @@ t.test("it ignores empty body objects", async (t) => {
hits: 1,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -598,6 +631,7 @@ t.test("it ignores body of graphql queries", async (t) => {
query: undefined,
auth: [{ type: "apiKey", in: "header", name: "x-api-key" }],
},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -681,6 +715,7 @@ t.test("it respects max samples", async (t) => {
query: undefined,
auth: undefined,
},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -712,6 +747,7 @@ t.test(
hits: 12,
graphql: undefined,
apispec: {},
graphQLSchema: undefined,
},
]);
}
Expand Down Expand Up @@ -750,6 +786,7 @@ t.test("with string format", async (t) => {
query: undefined,
auth: undefined,
},
graphQLSchema: undefined,
},
]);
});
Expand Down Expand Up @@ -798,6 +835,7 @@ t.test(
query: undefined,
auth: undefined,
},
graphQLSchema: undefined,
},
]);

Expand Down Expand Up @@ -830,6 +868,7 @@ t.test(
query: undefined,
auth: undefined,
},
graphQLSchema: undefined,
},
]);
}
Expand Down
24 changes: 23 additions & 1 deletion library/agent/Routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@ export type Route = {
};

export class Routes {
// Routes are only registered at the end of the request, so we need to store the schema in a separate map
private graphQLSchemas: Map<string, string> = new Map();
private routes: Map<string, Route> = new Map();

constructor(private readonly maxEntries: number = 1000) {}
constructor(
private readonly maxEntries: number = 1000,
private readonly maxGraphQLSchemas = 10
) {}

addRoute(context: Context) {
if (isAikidoDASTRequest(context)) {
Expand Down Expand Up @@ -63,6 +68,22 @@ export class Routes {
return `${method}:${path}`;
}

hasGraphQLSchema(method: string, path: string): boolean {
const key = this.getKey(method, path);

return this.graphQLSchemas.has(key);
}

setGraphQLSchema(method: string, path: string, schema: string) {
if (
schema.length > 0 &&
this.graphQLSchemas.size < this.maxGraphQLSchemas
) {
const key = this.getKey(method, path);
this.graphQLSchemas.set(key, schema);
}
}

private getGraphQLKey(
method: string,
path: string,
Expand Down Expand Up @@ -124,6 +145,7 @@ export class Routes {
hits: route.hits,
graphql: route.graphql,
apispec: route.apispec,
graphQLSchema: this.graphQLSchemas.get(key),
};
});
}
Expand Down
1 change: 1 addition & 0 deletions library/sources/Express.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ t.test("it adds body schema to stored routes", async (t) => {
query: undefined,
auth: undefined,
},
graphQLSchema: undefined,
},
]);
});
Expand Down
Loading

0 comments on commit 2871bb6

Please sign in to comment.