const _ = require('lodash/fp') const { mapSchema, getDirective, MapperKind } = require('@graphql-tools/utils') const { defaultFieldResolver } = require('graphql') const { AuthenticationError } = require('../errors') function authDirectiveTransformer(schema, directiveName = 'auth') { return mapSchema(schema, { // For object types [MapperKind.OBJECT_TYPE]: (objectType) => { const directive = getDirective(schema, objectType, directiveName)?.[0] if (directive) { const requiredAuthRole = directive.requires objectType._requiredAuthRole = requiredAuthRole } return objectType }, // For field definitions [MapperKind.OBJECT_FIELD]: (fieldConfig, _fieldName, typeName) => { const directive = getDirective(schema, fieldConfig, directiveName)?.[0] if (directive) { const requiredAuthRole = directive.requires fieldConfig._requiredAuthRole = requiredAuthRole } // Get the parent object type const objectType = schema.getType(typeName) // Apply auth check to the field's resolver const { resolve = defaultFieldResolver } = fieldConfig fieldConfig.resolve = function (root, args, context, info) { const requiredRoles = fieldConfig._requiredAuthRole || objectType._requiredAuthRole if (!requiredRoles) return resolve.apply(this, [root, args, context, info]) const user = context.req.session.user if (!user || !_.includes(_.upperCase(user.role), requiredRoles)) { throw new AuthenticationError('You do not have permission to access this resource!') } return resolve.apply(this, [root, args, context, info]) } return fieldConfig } }) } module.exports = authDirectiveTransformer