Skip to content
Snippets Groups Projects
Commit de1b10a0 authored by poka's avatar poka
Browse files

working but i think proxy is useless protection for row limiter...

parent 99891158
No related branches found
No related tags found
No related merge requests found
...@@ -8,3 +8,6 @@ ...@@ -8,3 +8,6 @@
# IDE files # IDE files
/.idea /.idea
# proxy limiter
proxy_limiter/node_modules
This diff is collapsed.
{
"name": "tata",
"version": "1.0.0",
"description": "",
"main": "server.js",
"dependencies": {
"@fastify/rate-limit": "^9.1.0",
"axios": "^1.6.8",
"fastify": "^4.26.2",
"graphql": "^16.8.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "ISC"
}
const fastify = require("fastify")();
const axios = require("axios");
const { parse, visit, Kind } = require("graphql");
const rateLimit = require("@fastify/rate-limit");
const HASURA_ENDPOINT = "http://localhost:8080";
const MAX_DEPTH = 5; // Set the maximum allowed depth
const MAX_ROWS = 5; // Set the maximum allowed rows per response
fastify.register(rateLimit, {
max: 100, // Maximum number of requests per time window
timeWindow: "1 minute", // Time window for rate limiting
});
// Function to calculate the depth of a GraphQL query
function getDepth(ast) {
let depth = 0;
visit(ast, {
[Kind.SELECTION_SET](node) {
depth++;
},
});
return depth;
}
// Function to check if a query is an introspection query
function isIntrospectionQuery(ast) {
let isIntrospection = false;
visit(ast, {
[Kind.FIELD](node) {
if (node.name.value === "__schema" || node.name.value === "__type") {
isIntrospection = true;
}
},
});
return isIntrospection;
}
// Function to count the number of rows in a response
function countRows(response) {
let count = 0;
function traverseObject(obj) {
for (const key in obj) {
if (Array.isArray(obj[key])) {
count += obj[key].length;
obj[key].forEach(traverseObject);
} else if (typeof obj[key] === "object") {
traverseObject(obj[key]);
}
}
}
traverseObject(response);
return count;
}
// Middleware function for depth, row count, and rate limiting checks
async function graphqlMiddleware(request, reply) {
try {
const query = request.body.query;
const parsedQuery = parse(query);
// Check if it's an introspection query
if (isIntrospectionQuery(parsedQuery)) {
// Forward the introspection query to Hasura and return the response
const response = await axios.post(
HASURA_ENDPOINT + request.url,
request.body,
{
headers: request.headers,
}
);
reply.status(response.status).send(response.data);
return;
}
// Check the depth of the GraphQL query
const depth = getDepth(parsedQuery);
if (depth > MAX_DEPTH) {
reply.status(400).send({
errors: [
{
message: `The query depth (${depth}) exceeds the allowed limit (${MAX_DEPTH})`,
},
],
});
return;
}
// Forward the request to Hasura and get the response
const response = await axios.post(
HASURA_ENDPOINT + request.url,
request.body,
{
headers: request.headers,
}
);
// Check the number of rows in the response
const rowCount = countRows(response.data);
if (rowCount > MAX_ROWS) {
reply.status(400).send({
errors: [
{
message: `The response contains too many rows (${rowCount}). The maximum allowed is ${MAX_ROWS}.`,
},
],
});
return;
}
// Forward Hasura's response to the client
reply.status(response.status).send(response.data);
} catch (error) {
// Handle request errors
reply
.status(error.response ? error.response.status : 500)
.send(error.response ? error.response.data : { message: error.message });
}
}
// Route for /v1/graphql
fastify.post("/v1/graphql", graphqlMiddleware);
// Route for /v1beta1/relay
fastify.post("/v1beta1/relay", graphqlMiddleware);
const start = async () => {
try {
await fastify.listen({ port: 3000, host: "0.0.0.0" });
console.log(`Server running on port ${fastify.server.address().port}`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment