Socket
Socket
Sign inDemoInstall

graphql-introspection-filtering

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

graphql-introspection-filtering - npm Package Compare versions

Comparing version 3.0.0-beta to 3.0.0

1

dist/index.js

@@ -16,3 +16,2 @@ "use strict";

Object.defineProperty(exports, "IntrospectionMapperKind", { enumerable: true, get: function () { return types_1.IntrospectionMapperKind; } });
// todo docs
//# sourceMappingURL=index.js.map

2

package.json
{
"name": "graphql-introspection-filtering",
"version": "3.0.0-beta",
"version": "3.0.0",
"description": "Filter graphql schema introspection result to hide restricted fields and types",

@@ -5,0 +5,0 @@ "main": "./dist/index.js",

@@ -32,6 +32,7 @@ # graphql-introspection-filtering

Filtering is possible on schemas created with `makeExecutableSchema`, provided by `graphql-introspection-filtering`.
To enable filtering, a mapper has to be applied to schema.
```
import makeExecutableSchema from 'graphql-introspection-filtering';
import makeExecutableSchema, { mapSchema } from 'graphql-introspection-filtering';
const schema = makeExecutableSchema(schemaConfig[, builder]);
export default mapSchema(makeExecutableSchema(schemaConfig[, builder]), mapper);
```

@@ -43,81 +44,68 @@

| Option | Type | Default | Description |
|---------------------|------------------------------------------|---------|-------------|
| Option | Type | Default | Description |
|---------------------|------------------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **shouldSkipQuery** | `null`, `number`, `(context) => boolean` | `null` | When positive number provided, this number of introspection queries will be unfiltered. Alternatively callback can be provided, it takes `context` as an argument, and should return boolean. |
| **hookDirectives** | `boolean`, `string[]` | `true` | Whether to hook directives, array of specific directive names can be provided |
- `builder` - builder function (default: original graphql `makeExecutableSchema`)
- `mapper` - introspection schema mapper
### Create introspection schema visitor
### Create introspection schema mapper
Every object and field is visited by a directive visitor, where corresponding directive is applied on it in
a schema definition (directives on directives are not allowed, so all directives pass this requirement)
**AND** assigned directive visitor contains a corresponding introspection visitor method.
a schema definition (directives configured separately) **AND** applied mapper contains a
corresponding introspection visitor method.
Directive visitor instance is created for every object and field it was applied to (and all directive definitions).
When *falsy* value is returned by a mapped resolver, the field / object is excluded from introspection result.
When *falsy* value is returned by a visitor, the field / object is excluded from introspection result.
Example introspection mapper can be found below.
Example introspection directive visitor below.
```ts
class AuthenticationDirective<TArgs = any, TContext = any> extends SchemaDirectiveVisitor<TArgs, TContext> implements IntrospectionDirectiveVisitor<TArgs, TContext> {
name: string; // name of the directive used in schema
args: TArgs; // arguments provided to directive
visitedType: VisitableSchemaType; // parent of visited object/field/...
context: TContext; // current query context
// (optional) If defined instance can visit field argument definitions
visitIntrospectionArgument(result: GraphQLArgument, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLArgument> {
return this.authenticate(result);
}
// (optional) If defined instance can visit `directive` definitions
visitIntrospectionDirective(result: GraphQLDirective, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLDirective> {
return this.authenticate(result);
}
// (optional) If defined instance can visit `enum` definitions
visitIntrospectionEnum(result: GraphQLEnumType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLEnumType> {
return this.authenticate(result);
}
// (optional) If defined instance can visit enum value definitions
visitIntrospectionEnumValue(result: GraphQLEnumValue, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLEnumValue> {
return this.authenticate(result);
}
// (optional) If defined instance can visit object field definitions
visitIntrospectionField(result: GraphQLField<any, any>, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLField<any, any>> {
return this.authenticate(result);
}
// (optional) If defined instance can visit input field definitions
visitIntrospectionInputField(result: GraphQLInputField, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLInputField> {
return this.authenticate(result);
}
// (optional) If defined instance can visit `input` object definitions
visitIntrospectionInputObject(result: GraphQLInputObjectType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLInputObjectType> {
return this.authenticate(result);
}
// (optional) If defined instance can visit `interface` definitions
visitIntrospectionInterface(result: GraphQLInterfaceType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLInterfaceType> {
return this.authenticate(result);
}
// (optional) If defined instance can visit object `type` definitions
visitIntrospectionObject(result: GraphQLObjectType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLObjectType> {
return this.authenticate(result);
}
// (optional) If defined instance can visit `scalar` definitions
visitIntrospectionScalar(result: GraphQLScalarType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLScalarType> {
return this.authenticate(result);
}
// (optional) If defined instance can visit `union` definitions
visitIntrospectionUnion(result: GraphQLUnionType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLUnionType> {
return this.authenticate(result);
}
}
export const mapper = {
// (optional) If defined instance can visit `scalar` definitions
[IntrospectionMapperKind.SCALAR_TYPE](result: GraphQLScalarType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit `enum` definitions
[IntrospectionMapperKind.ENUM_TYPE](result: GraphQLEnumType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit object `type` definitions
[IntrospectionMapperKind.OBJECT_TYPE](result: GraphQLObjectType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit `input` object definitions
[IntrospectionMapperKind.INPUT_OBJECT_TYPE](result: GraphQLInputObjectType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit `union` definitions
[IntrospectionMapperKind.UNION_TYPE](result: GraphQLUnionType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit `interface` definitions
[IntrospectionMapperKind.INTERFACE_TYPE](result: GraphQLInterfaceType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit enum value definitions
[IntrospectionMapperKind.ENUM_VALUE](result: GraphQLEnumValue, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit object field definitions
[IntrospectionMapperKind.OBJECT_FIELD](result: GraphQLField<any, any>, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit field argument definitions
[IntrospectionMapperKind.ARGUMENT](result: GraphQLArgument, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit input field definitions
[IntrospectionMapperKind.INPUT_OBJECT_FIELD](result: GraphQLInputField, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
// (optional) If defined instance can visit `directive` definitions
[IntrospectionMapperKind.DIRECTIVE](result: GraphQLDirective) {
return wrap(result, schema, resolver);
}
} satisfies IntrospectionSchemaMapper & SchemaMapper;
```

@@ -160,58 +148,102 @@

#### AuthenticationDirective
#### Authentication mapper
```ts
class AuthenticationDirective extends SchemaDirectiveVisitor implements IntrospectionDirectiveVisitor {
async authenticate(result: any) {
if (!this.context.roles.includes(this.args.requires || 'ADMIN')) {
return null;
}
return result;
}
visitIntrospectionArgument(result: GraphQLArgument, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLArgument> {
return this.authenticate(result);
}
type WrappedResolverType<TSource, TContext, TArgs = any, TResult = unknown> = (
directive: Record<string, any>, orig: GraphQLFieldResolver<TSource, TContext, TArgs, TResult>,
...passtrough: Parameters<GraphQLFieldResolver<TSource, TContext, TArgs>>
) => TResult;
visitIntrospectionDirective(result: GraphQLDirective, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLDirective> {
return this.authenticate(result);
}
const check = (context: ContextType, requiredPermission?: string) => {
// permission check
};
visitIntrospectionEnum(result: GraphQLEnumType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLEnumType> {
return this.authenticate(result);
}
const introspectionResolver = (
directive: Record<string, any>, orig: GraphQLFieldResolver<any, any>,
parent: unknown, args: Record<string, unknown>, context: ContextType, info: GraphQLResolveInfo
) => {
if (check(context, directive.requires)) {
return orig(parent, args, context, info);
}
visitIntrospectionEnumValue(result: GraphQLEnumValue, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLEnumValue> {
return this.authenticate(result);
}
return null;
};
visitIntrospectionField(result: GraphQLField<any, any>, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLField<any, any>> {
return this.authenticate(result);
}
const resolver = (
directive: Record<string, any>, orig: GraphQLFieldResolver<any, any>,
parent: unknown, args: Record<string, unknown>, context: ContextType, info: GraphQLResolveInfo
) => {
if (!check(context, directive.requires)) {
throw new ValidationError(`Cannot query field "${info.fieldName}" on type "${info.parentType.name}".`);
}
visitIntrospectionInputField(result: GraphQLInputField, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLInputField> {
return this.authenticate(result);
}
return orig(parent, args, context, info);
};
visitIntrospectionInputObject(result: GraphQLInputObjectType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLInputObjectType> {
return this.authenticate(result);
}
visitIntrospectionInterface(result: GraphQLInterfaceType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLInterfaceType> {
return this.authenticate(result);
}
type WrappableIntrospectionType = VisitableIntrospectionType & {
resolve: GraphQLFieldResolver<any, any> | null;
subscribe: GraphQLFieldResolver<any, any> | null; // not precise
}
visitIntrospectionObject(result: GraphQLObjectType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLObjectType> {
return this.authenticate(result);
}
const isWrappable = (val: any): val is WrappableIntrospectionType => !!val;
visitIntrospectionScalar(result: GraphQLScalarType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLScalarType> {
return this.authenticate(result);
}
const wrap = <T extends VisitableIntrospectionType>(result: T, schema: GraphQLSchema, resolver: WrappedResolverType<any, any>) => {
const directive = getDirective(schema, result as any, 'auth')?.[0];
if (directive && isWrappable(result)) {
const key = result.subscribe ? 'subscribe' : 'resolve';
const current = result[key];
visitIntrospectionUnion(result: GraphQLUnionType, info: GraphQLResolveInfo): IntrospectionVisitor<GraphQLUnionType> {
return this.authenticate(result);
result[key] = resolver.bind(undefined, directive, current || defaultFieldResolver);
}
return result;
};
export const authMapper = {
[IntrospectionMapperKind.SCALAR_TYPE](result: GraphQLScalarType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.ENUM_TYPE](result: GraphQLEnumType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.OBJECT_TYPE](result: GraphQLObjectType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.INPUT_OBJECT_TYPE](result: GraphQLInputObjectType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.UNION_TYPE](result: GraphQLUnionType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.INTERFACE_TYPE](result: GraphQLInterfaceType, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.ENUM_VALUE](result: GraphQLEnumValue, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.OBJECT_FIELD](result: GraphQLField<any, any>, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.ARGUMENT](result: GraphQLArgument, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.INPUT_OBJECT_FIELD](result: GraphQLInputField, parent: any, schema: GraphQLSchema) {
return wrap(result, schema, introspectionResolver);
},
[IntrospectionMapperKind.DIRECTIVE](result: GraphQLDirective) {
if (result.name === 'auth' && isWrappable(result)) {
result.resolve = () => null;
}
// ....
}
return result;
},
[MapperKind.ENUM_TYPE](result, schema) {
return wrap(result, schema, resolver);
},
[MapperKind.OBJECT_FIELD](result, _, __, schema) {
return wrap(result as any, schema, resolver);
},
[MapperKind.INPUT_OBJECT_FIELD](result, _, __, schema) {
return wrap(result as any, schema, resolver);
}
} satisfies IntrospectionSchemaMapper & SchemaMapper;
```

@@ -221,12 +253,8 @@

```ts
import makeExecutableSchema from 'graphql-introspection-filtering';
import makeExecutableSchema, { mapSchema } from 'graphql-introspection-filtering';
const schema = makeExecutableSchema({
export default mapSchema(makeExecutableSchema({
typeDefs: ...schema...,
...,
schemaDirectives: {
auth: AuthenticationDirective
},
shouldSkipQuery: 1 // skip initial query, which is executeted to hash schema
});
}), authMapper);
```

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc