@pothos/plugin-scope-auth
Version:
A Pothos plugin for adding scope based authorization checks to your GraphQL Schema
163 lines (162 loc) • 9.01 kB
JavaScript
import './global-types.js';
import './schema-builder.js';
import './field-builders.js';
import SchemaBuilder, { BasePlugin, PothosSchemaError, RootFieldBuilder } from '@pothos/core';
import { isTypeOfHelper } from './is-type-of-helper.js';
import RequestCache from './request-cache.js';
import { resolveHelper } from './resolve-helper.js';
import { createFieldAuthScopesStep, createFieldGrantScopesStep, createResolveStep, createTypeAuthScopesStep, createTypeGrantScopesStep } from './steps.js';
export { RequestCache };
export * from './errors.js';
export * from './types.js';
const pluginName = "scopeAuth";
export default pluginName;
let inResolveType = false;
export class PothosScopeAuthPlugin extends BasePlugin {
wrapResolve(resolver, fieldConfig) {
var _this_builder_options_scopeAuth, _this_builder_options_scopeAuth1;
if (this.options.disableScopeAuth) {
return resolver;
}
const typeConfig = this.buildCache.getTypeConfig(fieldConfig.parentType);
if (typeConfig.graphqlKind !== "Object" && typeConfig.graphqlKind !== "Interface") {
throw new PothosSchemaError(`Got fields for ${fieldConfig.parentType} which is a ${typeConfig.graphqlKind} which cannot have fields`);
}
const authorizedOnSubscribe = !!((_this_builder_options_scopeAuth = this.builder.options.scopeAuth) === null || _this_builder_options_scopeAuth === void 0 ? void 0 : _this_builder_options_scopeAuth.authorizeOnSubscribe) && typeConfig.kind === "Subscription";
const nonRoot = (typeConfig.graphqlKind === "Interface" || typeConfig.graphqlKind === "Object") && typeConfig.kind !== "Query" && typeConfig.kind !== "Mutation" && typeConfig.kind !== "Subscription";
var _typeConfig_pothosOptions_runScopesOnType, _ref;
const runTypeScopesOnField = !nonRoot || !((_ref = (_typeConfig_pothosOptions_runScopesOnType = typeConfig.pothosOptions.runScopesOnType) !== null && _typeConfig_pothosOptions_runScopesOnType !== void 0 ? _typeConfig_pothosOptions_runScopesOnType : (_this_builder_options_scopeAuth1 = this.builder.options.scopeAuth) === null || _this_builder_options_scopeAuth1 === void 0 ? void 0 : _this_builder_options_scopeAuth1.runScopesOnType) !== null && _ref !== void 0 ? _ref : false);
const steps = this.createResolveSteps(fieldConfig, typeConfig, resolver, runTypeScopesOnField, authorizedOnSubscribe);
if (steps.length > 1) {
return resolveHelper(steps, this, fieldConfig);
}
return resolver;
}
wrapSubscribe(subscriber, fieldConfig) {
var _this_builder_options_scopeAuth;
if (this.options.disableScopeAuth) {
return subscriber;
}
const typeConfig = this.buildCache.getTypeConfig(fieldConfig.parentType);
if (typeConfig.graphqlKind !== "Object" && typeConfig.graphqlKind !== "Interface") {
throw new PothosSchemaError(`Got fields for ${fieldConfig.parentType} which is a ${typeConfig.graphqlKind} which cannot have fields`);
}
if (!((_this_builder_options_scopeAuth = this.builder.options.scopeAuth) === null || _this_builder_options_scopeAuth === void 0 ? void 0 : _this_builder_options_scopeAuth.authorizeOnSubscribe) || typeConfig.kind !== "Subscription") {
return subscriber;
}
const steps = this.createSubscribeSteps(fieldConfig, typeConfig, subscriber);
if (steps.length > 1) {
return resolveHelper(steps, this, fieldConfig);
}
return subscriber;
}
wrapResolveType(resolveType) {
return (...args) => {
inResolveType = true;
try {
return resolveType(...args);
}
finally {
inResolveType = false;
}
};
}
wrapIsTypeOf(isTypeOf, typeConfig) {
var _this_builder_options_scopeAuth;
if (this.options.disableScopeAuth) {
return isTypeOf;
}
var _typeConfig_pothosOptions_runScopesOnType, _ref;
const shouldRunTypeScopes = (_ref = (_typeConfig_pothosOptions_runScopesOnType = typeConfig.pothosOptions.runScopesOnType) !== null && _typeConfig_pothosOptions_runScopesOnType !== void 0 ? _typeConfig_pothosOptions_runScopesOnType : (_this_builder_options_scopeAuth = this.builder.options.scopeAuth) === null || _this_builder_options_scopeAuth === void 0 ? void 0 : _this_builder_options_scopeAuth.runScopesOnType) !== null && _ref !== void 0 ? _ref : false;
if (!shouldRunTypeScopes) {
return isTypeOf;
}
const steps = this.createStepsForType(typeConfig, {
forField: false
});
if (steps.length === 0) {
return isTypeOf;
}
const runSteps = isTypeOfHelper(steps, this, isTypeOf);
return (source, context, info) => {
if (inResolveType) {
var _isTypeOf;
return (_isTypeOf = isTypeOf === null || isTypeOf === void 0 ? void 0 : isTypeOf(source, context, info)) !== null && _isTypeOf !== void 0 ? _isTypeOf : false;
}
return runSteps(source, context, info);
};
}
createStepsForType(typeConfig, { skipTypeScopes, skipInterfaceScopes, forField }) {
const parentAuthScope = typeConfig.pothosOptions.authScopes;
const parentGrantScopes = typeConfig.pothosOptions.grantScopes;
const interfaceConfigs = typeConfig.kind === "Object" || typeConfig.kind === "Interface" ? typeConfig.interfaces.map((iface) => this.buildCache.getTypeConfig(iface, "Interface")) : [];
const steps = [];
if (parentAuthScope && !skipTypeScopes) {
steps.push(createTypeAuthScopesStep(parentAuthScope, typeConfig.name));
}
if (!skipInterfaceScopes && !(typeConfig.kind === "Object" && typeConfig.pothosOptions.skipInterfaceScopes)) {
for (const interfaceConfig of interfaceConfigs) {
if (interfaceConfig.pothosOptions.authScopes) {
steps.push(createTypeAuthScopesStep(interfaceConfig.pothosOptions.authScopes, interfaceConfig.name));
}
}
}
if (parentGrantScopes) {
steps.push(createTypeGrantScopesStep(parentGrantScopes, typeConfig.name, forField));
}
return steps;
}
createResolveSteps(fieldConfig, typeConfig, resolver, shouldRunTypeScopes, authorizedOnSubscribe) {
var _ref, _ref1;
const stepsForType = shouldRunTypeScopes && !authorizedOnSubscribe ? this.createStepsForType(typeConfig, {
skipTypeScopes: (_ref = (fieldConfig.graphqlKind === "Interface" || fieldConfig.graphqlKind === "Object") && fieldConfig.pothosOptions.skipTypeScopes) !== null && _ref !== void 0 ? _ref : false,
skipInterfaceScopes: (_ref1 = (fieldConfig.graphqlKind === "Interface" || fieldConfig.kind === "Object") && fieldConfig.pothosOptions.skipInterfaceScopes) !== null && _ref1 !== void 0 ? _ref1 : false,
forField: true
}) : [];
const fieldAuthScopes = fieldConfig.pothosOptions.authScopes;
const fieldGrantScopes = fieldConfig.pothosOptions.grantScopes;
const steps = [
...stepsForType
];
if (fieldAuthScopes && !authorizedOnSubscribe) {
steps.push(createFieldAuthScopesStep(fieldAuthScopes));
}
steps.push(createResolveStep(resolver));
if (fieldGrantScopes) {
steps.push(createFieldGrantScopesStep(fieldGrantScopes));
}
return steps;
}
createSubscribeSteps(fieldConfig, typeConfig, subscriber) {
var _ref, _ref1;
const stepsForType = this.createStepsForType(typeConfig, {
skipTypeScopes: (_ref = (fieldConfig.graphqlKind === "Interface" || fieldConfig.graphqlKind === "Object") && fieldConfig.pothosOptions.skipTypeScopes) !== null && _ref !== void 0 ? _ref : false,
skipInterfaceScopes: (_ref1 = (fieldConfig.graphqlKind === "Interface" || fieldConfig.kind === "Object") && fieldConfig.pothosOptions.skipInterfaceScopes) !== null && _ref1 !== void 0 ? _ref1 : false,
forField: true
});
const fieldAuthScopes = fieldConfig.pothosOptions.authScopes;
const steps = [
...stepsForType
];
if (fieldAuthScopes) {
steps.push(createFieldAuthScopesStep(fieldAuthScopes));
}
steps.push(createResolveStep(subscriber));
return steps;
}
}
const fieldBuilderProto = RootFieldBuilder.prototype;
fieldBuilderProto.authField = function authField(options) {
return this.field(options);
};
SchemaBuilder.registerPlugin(pluginName, PothosScopeAuthPlugin, {
v3: (options) => ({
scopeAuthOptions: undefined,
authScopes: undefined,
scopeAuth: {
...options.scopeAuthOptions,
authScopes: options.authScopes
}
})
});
//# sourceMappingURL=index.js.map