UNPKG

graphql-shield

Version:

GraphQL Server permissions as another layer of abstraction!

110 lines (109 loc) 4.84 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.shield = exports.getFragmentReplacements = exports.normalizeOptions = void 0; const tslib_1 = require("tslib"); const object_hash_1 = tslib_1.__importDefault(require("object-hash")); const resolvers_composition_1 = require("@graphql-tools/resolvers-composition"); const schema_1 = require("@graphql-tools/schema"); const wrap_1 = require("@graphql-tools/wrap"); const constructors_js_1 = require("./constructors.js"); const utils_js_1 = require("./utils.js"); const getResolversFromSchema_js_1 = require("./getResolversFromSchema.js"); const validation_js_1 = require("./validation.js"); const generator_js_1 = require("./generator.js"); const replaceFieldWithFragment_js_1 = require("./replaceFieldWithFragment.js"); const fragments_js_1 = require("./fragments.js"); /** * * @param options * * Makes sure all of defined rules are in accord with the options * shield can process. * */ function normalizeOptions(options) { if (typeof options.fallbackError === 'string') { options.fallbackError = new Error(options.fallbackError); } return { debug: options.debug !== undefined ? options.debug : false, allowExternalErrors: (0, utils_js_1.withDefault)(false)(options.allowExternalErrors), fallbackRule: (0, utils_js_1.withDefault)(constructors_js_1.allow)(options.fallbackRule), fallbackError: (0, utils_js_1.withDefault)(new Error('Not Authorised!'))(options.fallbackError), hashFunction: (0, utils_js_1.withDefault)(object_hash_1.default)(options.hashFunction), disableFragmentsAndPostExecRules: (0, utils_js_1.withDefault)(false)(options.disableFragmentsAndPostExecRules), }; } exports.normalizeOptions = normalizeOptions; function middlewareToCompositionResolver(middlewareWithOptions) { const { resolve } = middlewareWithOptions; if (resolve) { return (next) => (root, args, context, info) => resolve(next, root, args, context, info); } return (next) => (root, args, context, info) => next(root, args, context, info); } function getFragmentReplacements(middleware) { const fragmentReplacements = Object.entries(middleware).reduce((result, [objectName, objectFields]) => { Object.entries(objectFields).forEach(([fieldName, middlewareFunction]) => { const { fragment, fragments } = middlewareFunction; if (fragment) { result.push({ field: fieldName, fragment, }); } if (fragments) { for (const fragment of fragments) { result.push({ field: fieldName, fragment: fragment, }); } } }); return result; }, []); return (0, fragments_js_1.prepareFragmentReplacements)(fragmentReplacements); } exports.getFragmentReplacements = getFragmentReplacements; function applyComposition(schema, middleware) { const compositionRules = Object.entries(middleware).reduce((result, [objectName, objectFields]) => { Object.entries(objectFields).forEach(([fieldName, middlewareFunction]) => { const compositionResolver = middlewareToCompositionResolver(middlewareFunction); result[`${objectName}.${fieldName}`] = [compositionResolver]; }); return result; }, {}); const originalResolvers = (0, getResolversFromSchema_js_1.getResolversFromSchema)(schema, true, true); const resolvers = (0, resolvers_composition_1.composeResolvers)(originalResolvers, compositionRules); return (0, schema_1.addResolversToSchema)({ schema, resolvers }); } /** * * @param schema * @param ruleTree * @param options * * Validates rules and applies defined rule tree to the schema. * */ function shield(schema, ruleTree, options = {}) { const normalizedOptions = normalizeOptions(options); const ruleTreeValidity = (0, validation_js_1.validateRuleTree)(ruleTree); if (ruleTreeValidity.status === 'ok') { const middleware = (0, generator_js_1.generateMiddlewareFromSchemaAndRuleTree)(schema, ruleTree, normalizedOptions); if (normalizedOptions.disableFragmentsAndPostExecRules) { return applyComposition(schema, middleware); } const fragmentReplacements = getFragmentReplacements(middleware); const wrappedSchema = (0, wrap_1.wrapSchema)({ schema, transforms: [new replaceFieldWithFragment_js_1.ReplaceFieldWithFragment(fragmentReplacements || [])], }); return applyComposition(wrappedSchema, middleware); } else { throw new validation_js_1.ValidationError(ruleTreeValidity.message); } } exports.shield = shield;