Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 37 additions & 2 deletions README.md
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a version for the @escape.tech/graphql-armor@^3 module to keep track of and understand which version was tested and works perfectly with it.

and there's no need to elaborate on the explanation in the "using AutoLoad" example.

Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ app.get('/login', (req, res) => res.send("OK"));
/**
* Graphql Express
* @function GraphqlExpress
* @modules [graphql graphql-yoga@^4 ws@^8 graphql-ws@^5]
* @modules [graphql graphql-yoga@^4 ws@^8 graphql-ws@^5 @escape.tech/graphql-armor]
* @envs []
* @param {object} the express app
* @param {array} [{
Expand All @@ -153,6 +153,7 @@ app.get('/login', (req, res) => res.send("OK"));
* @param {object} the options {
* serverWS, // the express server
* yogaOptions, // see: https://the-guild.dev/graphql/yoga-server/docs
* armorOptions, // GraphQL Armor security configuration
* }
* @return {object} express app.next()
*
Expand All @@ -163,6 +164,29 @@ app.get('/login', (req, res) => res.send("OK"));
const server = app.listen(5000);
GraphqlExpress(app, [{ typeDefs: '', resolvers: {} }], { serverWS: server, yogaOptions: {} });
*
* @example setup Graphql with Armor security:
-------------------------------------------
import express from 'express';
const app = express();
const server = app.listen(5000);

// Basic security configuration
const armorOptions = {
maxAliases: 0, // Disable aliases completely
maxDepth: 10, // Limit query depth
maxCost: 1000, // Cost-based limiting
maxDirectives: 5, // Limit directive usage
maxArguments: 10, // Limit arguments per field
blockFieldSuggestion: true, // Block field suggestions
disableIntrospection: false // Keep introspection for development
};
*
* GraphqlExpress(app, [{ typeDefs: '', resolvers: {} }], {
* serverWS: server,
* yogaOptions: {},
* armorOptions
* });
*
* @example server WebSocket:
---------------------------
const { createPubSub } = await import('graphql-yoga');
Expand Down Expand Up @@ -196,6 +220,17 @@ GraphqlExpress(app, [{ typeDefs: '', resolvers: {} }], { serverWS: server, yogaO
AutoLoad(["typeDefs", "directives", "resolvers"]).then(schemas => {
GraphqlExpress(app, schemas, { serverWS: server, yogaOptions: {} });
});

// using AutoLoad with Armor security
AutoLoad(["typeDefs", "directives", "resolvers"]).then(schemas => {
const armorOptions = {
maxAliases: 0,
maxDepth: 10,
maxCost: 1000,
blockFieldSuggestion: true
};
GraphqlExpress(app, schemas, { serverWS: server, yogaOptions: {}, armorOptions });
});
```

#### Elastic Indexer Express
Expand Down Expand Up @@ -616,7 +651,7 @@ logger.info('...', '...');
- 9200:9200
- 9300:9300
kibana:
image: kibana
image: kibana@escape.tech/graphql-armor
ports:
- 5601:5601
environment:
Expand Down
41 changes: 38 additions & 3 deletions infrastructures/graphql-express.js
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a version for the @escape.tech/graphql-armor@^3 module to keep track of and understand which version was tested and works perfectly with it.

Please add documentation, in the form of /** * Config Armor plugin */, to the section regarding Armor settings.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DynamicImport } from '../utils/dynamic-import.js';
import { Logger } from '../utils/logger.js';

/**
* Graphql Express
Expand All @@ -18,6 +19,7 @@ import { DynamicImport } from '../utils/dynamic-import.js';
* @param {object} the options {
* serverWS, // the express server
* yogaOptions, // see: https://the-guild.dev/graphql/yoga-server/docs
* armorOptions, // New parameter for Armor configuration
* }
* @return {promise} is done
*
Expand All @@ -26,7 +28,7 @@ import { DynamicImport } from '../utils/dynamic-import.js';
import express from 'express';
const app = express();
const server = app.listen(5000);
GraphqlExpress(app, [{ typeDefs: '', resolvers: {} }], { serverWS: server, yogaOptions: {} });
GraphqlExpress(app, [{ typeDefs: '', resolvers: {} }], { serverWS: server, yogaOptions: {}, armorOptions: {} });
*
* @example server WebSocket:
---------------------------
Expand Down Expand Up @@ -57,7 +59,11 @@ import { DynamicImport } from '../utils/dynamic-import.js';
});
*/

export async function GraphqlExpress(app, schemas, { serverWS, yogaOptions } = {}) {
export async function GraphqlExpress(app, schemas, {
serverWS,
yogaOptions,
armorOptions = {} // New parameter for Armor configuration
} = {}) {

/*
* Imports
Expand All @@ -66,6 +72,8 @@ export async function GraphqlExpress(app, schemas, { serverWS, yogaOptions } = {
const { WebSocketServer } = await DynamicImport('ws@^8');
const { useServer } = await DynamicImport('graphql-ws/lib/use/ws');
await DynamicImport('graphql@^16');
const { GraphQLArmor } = await DynamicImport('@escape.tech/graphql-armor');
const logger = await Logger();


/*
Expand Down Expand Up @@ -136,7 +144,34 @@ export async function GraphqlExpress(app, schemas, { serverWS, yogaOptions } = {
/*
* Create graphql route
*/
app.use('/graphql', createYoga({ schema, graphiql: true, ...yogaOptions }));
// Configure GraphQL Armor with provided options or defaults
const defaultArmorOptions = {
maxDepth: 10,
maxDirectives: 5,
maxArguments: 10,
maxCost: 1000,
maxAliases: 0, // Disable aliases by default
blockFieldSuggestion: true,
disableIntrospection: false, // Keep introspection for development
onError: (error) => {
logger.warn('GraphQL Armor blocked query', {
type: error.type,
message: error.message,
query: error.query
});
}
};

const finalArmorOptions = { ...defaultArmorOptions, ...armorOptions };

const armor = new GraphQLArmor(finalArmorOptions);

app.use('/graphql', createYoga({
schema,
graphiql: true,
plugins: [armor.plugin()],
...yogaOptions
}));


/*
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@
"eslint-config-google": "^0.14.0",
"mocha": "^10.2.0"
}
}
}
Loading