From e818537fe9f033b62e712e1fac5ba3539ba9a1ed Mon Sep 17 00:00:00 2001 From: James Date: Wed, 8 Jul 2020 11:00:50 -0400 Subject: [PATCH] renames policy to access --- demo/{policies => access}/checkRole.js | 0 demo/{policies => access}/roles.js | 0 demo/collections/Admin.js | 16 +-- demo/collections/AllFields.js | 8 +- demo/collections/File.js | 12 +- demo/collections/FlexibleContent.js | 2 +- demo/collections/Hooks.js | 2 +- demo/collections/Localized.js | 2 +- demo/collections/LocalizedRepeater.js | 2 +- demo/collections/Media.js | 2 +- demo/collections/NestedRepeater.js | 2 +- demo/collections/PublicUsers.js | 14 +-- demo/collections/RelationshipA.js | 2 +- demo/collections/RelationshipB.js | 2 +- demo/collections/StrictPolicies.js | 10 +- demo/collections/Validations.js | 2 +- demo/globals/FlexibleGlobal.js | 4 +- ...hPolicies.js => GlobalWithStrictAccess.js} | 8 +- demo/globals/NavigationRepeater.js | 4 +- demo/payload.config.js | 10 +- .../{executePolicy.js => executeAccess.js} | 8 +- src/auth/getExecuteStaticAccess.js | 40 ++++++ src/auth/getExecuteStaticPolicy.js | 56 +++++---- .../resolvers/{policies.js => access.js} | 4 +- src/auth/graphql/resolvers/index.js | 4 +- .../operations/{policies.js => access.js} | 18 +-- src/auth/operations/index.js | 4 +- src/auth/operations/register.js | 10 +- src/auth/operations/update.js | 10 +- .../{policies.js => access.js} | 4 +- src/auth/requestHandlers/index.js | 4 +- src/client/components/data/User.js | 4 +- src/collections/operations/create.js | 10 +- src/collections/operations/delete.js | 6 +- src/collections/operations/find.js | 8 +- src/collections/operations/findByID.js | 8 +- src/collections/operations/update.js | 10 +- src/collections/sanitize.js | 2 +- src/express/static.js | 4 +- src/fields/performFieldOperations.js | 6 +- src/fields/sanitize.js | 4 +- src/globals/operations/findOne.js | 8 +- src/globals/operations/update.js | 10 +- src/globals/sanitize.js | 2 +- src/graphql/index.js | 6 +- src/graphql/schema/buildPoliciesType.js | 94 +++++++-------- src/index.js | 4 +- src/mongoose/buildSchema.js | 114 ++++++++---------- 48 files changed, 290 insertions(+), 276 deletions(-) rename demo/{policies => access}/checkRole.js (100%) rename demo/{policies => access}/roles.js (100%) rename demo/globals/{GlobalWithPolicies.js => GlobalWithStrictAccess.js} (69%) rename src/auth/{executePolicy.js => executeAccess.js} (58%) create mode 100644 src/auth/getExecuteStaticAccess.js rename src/auth/graphql/resolvers/{policies.js => access.js} (87%) rename src/auth/operations/{policies.js => access.js} (80%) rename src/auth/requestHandlers/{policies.js => access.js} (76%) diff --git a/demo/policies/checkRole.js b/demo/access/checkRole.js similarity index 100% rename from demo/policies/checkRole.js rename to demo/access/checkRole.js diff --git a/demo/policies/roles.js b/demo/access/roles.js similarity index 100% rename from demo/policies/roles.js rename to demo/access/roles.js diff --git a/demo/collections/Admin.js b/demo/collections/Admin.js index 4f6b2d631..6f88c192d 100644 --- a/demo/collections/Admin.js +++ b/demo/collections/Admin.js @@ -1,7 +1,7 @@ -const roles = require('../policies/roles'); -const checkRole = require('../policies/checkRole'); +const roles = require('../access/roles'); +const checkRole = require('../access/checkRole'); -const policy = ({ req: { user } }) => { +const access = ({ req: { user } }) => { const result = checkRole(['admin'], user); return result; }; @@ -13,11 +13,11 @@ module.exports = { plural: 'Admins', }, useAsTitle: 'email', - policies: { - create: policy, - read: policy, - update: policy, - delete: policy, + access: { + create: access, + read: access, + update: access, + delete: access, admin: () => true, }, auth: { diff --git a/demo/collections/AllFields.js b/demo/collections/AllFields.js index b2420a70f..70044e397 100644 --- a/demo/collections/AllFields.js +++ b/demo/collections/AllFields.js @@ -1,4 +1,4 @@ -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); const Email = require('../content-blocks/Email'); const Quote = require('../content-blocks/Quote'); const NumberBlock = require('../content-blocks/Number'); @@ -18,7 +18,7 @@ const AllFields = { return null; }, - policies: { + access: { read: () => true, }, fields: [ @@ -29,7 +29,7 @@ const AllFields = { required: true, defaultValue: 'Default Value', unique: true, - policies: { + access: { create: ({ req: { user } }) => checkRole(['admin'], user), update: ({ req: { user } }) => checkRole(['admin'], user), read: ({ req: { user } }) => Boolean(user), @@ -154,7 +154,7 @@ const AllFields = { label: 'Repeater Text 2', type: 'text', required: true, - policies: { + access: { read: ({ req: { user } }) => Boolean(user), update: ({ req: { user } }) => { return checkRole(['admin'], user); diff --git a/demo/collections/File.js b/demo/collections/File.js index e4f05496b..8a71d3c7a 100644 --- a/demo/collections/File.js +++ b/demo/collections/File.js @@ -1,7 +1,7 @@ const path = require('path'); -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); -const policy = ({ req: { user } }) => { +const access = ({ req: { user } }) => { const isAdmin = checkRole(['admin'], user); if (isAdmin) { @@ -27,11 +27,11 @@ module.exports = { staticURL: '/files', staticDir: path.resolve(__dirname, '../files'), }, - policies: { + access: { create: () => true, - read: policy, - update: policy, - delete: policy, + read: access, + update: access, + delete: access, }, useAsTitle: 'filename', fields: [ diff --git a/demo/collections/FlexibleContent.js b/demo/collections/FlexibleContent.js index 543d7fa73..ce53221f5 100644 --- a/demo/collections/FlexibleContent.js +++ b/demo/collections/FlexibleContent.js @@ -9,7 +9,7 @@ module.exports = { singular: 'Flexible Content', plural: 'Flexible Content', }, - policies: { + access: { read: () => true, }, fields: [ diff --git a/demo/collections/Hooks.js b/demo/collections/Hooks.js index 841bfc0cf..925531d97 100644 --- a/demo/collections/Hooks.js +++ b/demo/collections/Hooks.js @@ -6,7 +6,7 @@ module.exports = { plural: 'Hooks', }, useAsTitle: 'title', - policies: { + access: { create: () => true, read: () => true, update: () => true, diff --git a/demo/collections/Localized.js b/demo/collections/Localized.js index 368b4954e..2013424e3 100644 --- a/demo/collections/Localized.js +++ b/demo/collections/Localized.js @@ -5,7 +5,7 @@ module.exports = { plural: 'Localized Posts', }, useAsTitle: 'title', - policies: { + access: { read: () => true, }, preview: (doc, token) => { diff --git a/demo/collections/LocalizedRepeater.js b/demo/collections/LocalizedRepeater.js index ed2449da4..7b26edf27 100644 --- a/demo/collections/LocalizedRepeater.js +++ b/demo/collections/LocalizedRepeater.js @@ -4,7 +4,7 @@ const LocalizedRepeaters = { singular: 'Localized Repeater', plural: 'Localized Repeaters', }, - policies: { + access: { read: () => true, }, fields: [ diff --git a/demo/collections/Media.js b/demo/collections/Media.js index 668361041..bdd41bac0 100644 --- a/demo/collections/Media.js +++ b/demo/collections/Media.js @@ -6,7 +6,7 @@ module.exports = { singular: 'Media', plural: 'Media', }, - policies: { + access: { read: () => true, }, upload: { diff --git a/demo/collections/NestedRepeater.js b/demo/collections/NestedRepeater.js index 127cadeec..a8b6f8643 100644 --- a/demo/collections/NestedRepeater.js +++ b/demo/collections/NestedRepeater.js @@ -4,7 +4,7 @@ const NestedRepeater = { singular: 'Nested Repeater', plural: 'Nested Repeaters', }, - policies: { + access: { read: () => true, }, fields: [ diff --git a/demo/collections/PublicUsers.js b/demo/collections/PublicUsers.js index a13d44d74..c27f0fe69 100644 --- a/demo/collections/PublicUsers.js +++ b/demo/collections/PublicUsers.js @@ -1,6 +1,6 @@ -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); -const policy = ({ req: { user } }) => checkRole(['admin'], user); +const access = ({ req: { user } }) => checkRole(['admin'], user); module.exports = { slug: 'public-users', @@ -9,7 +9,7 @@ module.exports = { plural: 'Public Users', }, useAsTitle: 'email', - policies: { + access: { admin: () => false, create: () => true, read: () => true, @@ -38,10 +38,10 @@ module.exports = { label: 'This field should only be readable and editable by Admins with "admin" role', type: 'text', defaultValue: 'test', - policies: { - create: policy, - read: policy, - update: policy, + access: { + create: access, + read: access, + update: access, }, }, ], diff --git a/demo/collections/RelationshipA.js b/demo/collections/RelationshipA.js index b634b5ed7..ee9cbd568 100644 --- a/demo/collections/RelationshipA.js +++ b/demo/collections/RelationshipA.js @@ -1,6 +1,6 @@ module.exports = { slug: 'relationship-a', - policies: { + access: { read: () => true, }, labels: { diff --git a/demo/collections/RelationshipB.js b/demo/collections/RelationshipB.js index 619eb2722..ea0d0e603 100644 --- a/demo/collections/RelationshipB.js +++ b/demo/collections/RelationshipB.js @@ -1,6 +1,6 @@ module.exports = { slug: 'relationship-b', - policies: { + access: { read: () => true, }, labels: { diff --git a/demo/collections/StrictPolicies.js b/demo/collections/StrictPolicies.js index 09c71812c..477101bb8 100644 --- a/demo/collections/StrictPolicies.js +++ b/demo/collections/StrictPolicies.js @@ -1,13 +1,13 @@ -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); module.exports = { - slug: 'strict-policies', + slug: 'strict-access', labels: { - singular: 'Strict Policy', - plural: 'Strict Policies', + singular: 'Strict Access', + plural: 'Strict Access', }, useAsTitle: 'email', - policies: { + access: { create: () => true, read: ({ req: { user } }) => { if (checkRole(['admin'], user)) { diff --git a/demo/collections/Validations.js b/demo/collections/Validations.js index 6d264733d..623d8b097 100644 --- a/demo/collections/Validations.js +++ b/demo/collections/Validations.js @@ -4,7 +4,7 @@ module.exports = { singular: 'Validation', plural: 'Validations', }, - policies: { + access: { read: () => true, }, fields: [ diff --git a/demo/globals/FlexibleGlobal.js b/demo/globals/FlexibleGlobal.js index 95867ccd3..8f61836cc 100644 --- a/demo/globals/FlexibleGlobal.js +++ b/demo/globals/FlexibleGlobal.js @@ -1,11 +1,11 @@ -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); const Quote = require('../content-blocks/Quote'); const CallToAction = require('../content-blocks/CallToAction'); module.exports = { slug: 'flexible-global', label: 'Flexible Global', - policies: { + access: { update: ({ req: { user } }) => checkRole(['admin'], user), read: () => true, }, diff --git a/demo/globals/GlobalWithPolicies.js b/demo/globals/GlobalWithStrictAccess.js similarity index 69% rename from demo/globals/GlobalWithPolicies.js rename to demo/globals/GlobalWithStrictAccess.js index ad43109be..77d193d4b 100644 --- a/demo/globals/GlobalWithPolicies.js +++ b/demo/globals/GlobalWithStrictAccess.js @@ -1,9 +1,9 @@ -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); module.exports = { - slug: 'global-with-policies', - label: 'Global with Policies', - policies: { + slug: 'global-with-access', + label: 'Global with Strict Access', + access: { update: ({ req: { user } }) => checkRole(['admin'], user), read: ({ req: { user } }) => checkRole(['admin'], user), }, diff --git a/demo/globals/NavigationRepeater.js b/demo/globals/NavigationRepeater.js index 0aa35d172..79d458347 100644 --- a/demo/globals/NavigationRepeater.js +++ b/demo/globals/NavigationRepeater.js @@ -1,9 +1,9 @@ -const checkRole = require('../policies/checkRole'); +const checkRole = require('../access/checkRole'); module.exports = { slug: 'navigation-repeater', label: 'Navigation Repeater', - policies: { + access: { update: ({ req: { user } }) => checkRole(['admin', 'user'], user), read: () => true, }, diff --git a/demo/payload.config.js b/demo/payload.config.js index 30afda498..3bdaf5ff6 100644 --- a/demo/payload.config.js +++ b/demo/payload.config.js @@ -22,7 +22,7 @@ const Validations = require('./collections/Validations'); const FlexibleGlobal = require('./globals/FlexibleGlobal'); const NavigationRepeater = require('./globals/NavigationRepeater'); -const GlobalWithPolicies = require('./globals/GlobalWithPolicies'); +const GlobalWithStrictAccess = require('./globals/GlobalWithStrictAccess'); module.exports = { admin: { @@ -53,7 +53,7 @@ module.exports = { ], globals: [ NavigationRepeater, - GlobalWithPolicies, + GlobalWithStrictAccess, FlexibleGlobal, ], cookiePrefix: 'payload', @@ -89,11 +89,9 @@ module.exports = { }, }, hooks: { - afterError: (err, response) => { + afterError: () => { console.error('global error config handler'); }, }, - webpack: (config) => { - return config; - }, + webpack: (config) => config, }; diff --git a/src/auth/executePolicy.js b/src/auth/executeAccess.js similarity index 58% rename from src/auth/executePolicy.js rename to src/auth/executeAccess.js index 91df41d9d..322d8bb2e 100644 --- a/src/auth/executePolicy.js +++ b/src/auth/executeAccess.js @@ -1,8 +1,8 @@ const { Forbidden } = require('../errors'); -const executePolicy = async (operation, policy) => { - if (policy) { - const result = await policy(operation); +const executeAccess = async (operation, access) => { + if (access) { + const result = await access(operation); if (!result) { throw new Forbidden(); @@ -18,4 +18,4 @@ const executePolicy = async (operation, policy) => { throw new Forbidden(); }; -module.exports = executePolicy; +module.exports = executeAccess; diff --git a/src/auth/getExecuteStaticAccess.js b/src/auth/getExecuteStaticAccess.js new file mode 100644 index 000000000..7467cb168 --- /dev/null +++ b/src/auth/getExecuteStaticAccess.js @@ -0,0 +1,40 @@ +const executeStatic = require('./executeAccess'); +const { Forbidden } = require('../errors'); + +const getExecuteStaticPolicy = ({ config, Model }) => async (req, res, next) => { + try { + if (req.path) { + const policyResult = await executeStatic({ req, isReadingStaticFile: true }, config.access.read); + + if (typeof policyResult === 'object') { + const filename = decodeURI(req.path).replace(/^\/|\/$/g, ''); + + const queryToBuild = { + where: { + and: [ + { + filename: { + equals: filename, + }, + }, + policyResult, + ], + }, + }; + + const query = await Model.buildQuery(queryToBuild, req.locale); + const doc = await Model.findOne(query); + + if (!doc) { + throw new Forbidden(); + } + } + } + + return next(); + } catch (error) { + return next(error); + } +}; + +module.exports = getExecuteStaticPolicy; diff --git a/src/auth/getExecuteStaticPolicy.js b/src/auth/getExecuteStaticPolicy.js index 837767144..0403a25b3 100644 --- a/src/auth/getExecuteStaticPolicy.js +++ b/src/auth/getExecuteStaticPolicy.js @@ -1,42 +1,40 @@ -const executePolicy = require('./executePolicy'); +const executePolicy = require('./executeAccess'); const { Forbidden } = require('../errors'); -const getExecuteStaticPolicy = ({ config, Model }) => { - return async (req, res, next) => { - try { - if (req.path) { - const policyResult = await executePolicy({ req, isReadingStaticFile: true }, config.policies.read); +const getExecuteStaticPolicy = ({ config, Model }) => async (req, res, next) => { + try { + if (req.path) { + const policyResult = await executePolicy({ req, isReadingStaticFile: true }, config.policies.read); - if (typeof policyResult === 'object') { - const filename = decodeURI(req.path).replace(/^\/|\/$/g, ''); + if (typeof policyResult === 'object') { + const filename = decodeURI(req.path).replace(/^\/|\/$/g, ''); - const queryToBuild = { - where: { - and: [ - { - filename: { - equals: filename, - }, + const queryToBuild = { + where: { + and: [ + { + filename: { + equals: filename, }, - policyResult, - ], - }, - }; + }, + policyResult, + ], + }, + }; - const query = await Model.buildQuery(queryToBuild, req.locale); - const doc = await Model.findOne(query); + const query = await Model.buildQuery(queryToBuild, req.locale); + const doc = await Model.findOne(query); - if (!doc) { - throw new Forbidden(); - } + if (!doc) { + throw new Forbidden(); } } - - return next(); - } catch (error) { - return next(error); } - }; + + return next(); + } catch (error) { + return next(error); + } }; module.exports = getExecuteStaticPolicy; diff --git a/src/auth/graphql/resolvers/policies.js b/src/auth/graphql/resolvers/access.js similarity index 87% rename from src/auth/graphql/resolvers/policies.js rename to src/auth/graphql/resolvers/access.js index afdc8c726..8b207178a 100644 --- a/src/auth/graphql/resolvers/policies.js +++ b/src/auth/graphql/resolvers/access.js @@ -1,4 +1,4 @@ -const { policies } = require('../../operations'); +const { access } = require('../../operations'); const formatName = require('../../../graphql/utilities/formatName'); const formatConfigNames = (results, configs) => { @@ -19,7 +19,7 @@ const policyResolver = config => async (_, __, context) => { req: context, }; - let policyResults = await policies(options); + let policyResults = await access(options); policyResults = formatConfigNames(policyResults, config.collections); policyResults = formatConfigNames(policyResults, config.globals); diff --git a/src/auth/graphql/resolvers/index.js b/src/auth/graphql/resolvers/index.js index a814270fa..1a5be0daf 100644 --- a/src/auth/graphql/resolvers/index.js +++ b/src/auth/graphql/resolvers/index.js @@ -6,7 +6,7 @@ const init = require('./init'); const forgotPassword = require('./forgotPassword'); const resetPassword = require('./resetPassword'); const update = require('./update'); -const policies = require('./policies'); +const access = require('./access'); module.exports = { login, @@ -17,5 +17,5 @@ module.exports = { forgotPassword, resetPassword, update, - policies, + access, }; diff --git a/src/auth/operations/policies.js b/src/auth/operations/access.js similarity index 80% rename from src/auth/operations/policies.js rename to src/auth/operations/access.js index e18926831..5ced85042 100644 --- a/src/auth/operations/policies.js +++ b/src/auth/operations/access.js @@ -1,6 +1,6 @@ const allOperations = ['create', 'read', 'update', 'delete']; -const policies = async (args) => { +const access = async (args) => { const { config, req, @@ -13,9 +13,9 @@ const policies = async (args) => { const isLoggedIn = !!(user); const userCollectionConfig = (user && user.collection) ? config.collections.find((collection) => collection.slug === user.collection) : null; - const createPolicyPromise = async (obj, policy, operation, disableWhere = false) => { + const createPolicyPromise = async (obj, access, operation, disableWhere = false) => { const updatedObj = obj; - const result = await policy({ req }); + const result = await access({ req }); if (typeof result === 'object' && !disableWhere) { updatedObj[operation] = { @@ -36,8 +36,8 @@ const policies = async (args) => { if (field.name) { if (!updatedObj[field.name]) updatedObj[field.name] = {}; - if (field.policies && typeof field.policies[operation] === 'function') { - promises.push(createPolicyPromise(updatedObj[field.name], field.policies[operation], operation, true)); + if (field.access && typeof field.access[operation] === 'function') { + promises.push(createPolicyPromise(updatedObj[field.name], field.access[operation], operation, true)); } else { updatedObj[field.name][operation] = { permission: isLoggedIn, @@ -62,8 +62,8 @@ const policies = async (args) => { operations.forEach((operation) => { executeFieldPolicies(results[entity.slug].fields, entity.fields, operation); - if (typeof entity.policies[operation] === 'function') { - promises.push(createPolicyPromise(results[entity.slug], entity.policies[operation], operation)); + if (typeof entity.access[operation] === 'function') { + promises.push(createPolicyPromise(results[entity.slug], entity.access[operation], operation)); } else { results[entity.slug][operation] = { permission: isLoggedIn, @@ -73,7 +73,7 @@ const policies = async (args) => { }; if (userCollectionConfig) { - results.canAccessAdmin = userCollectionConfig.policies.admin ? userCollectionConfig.policies.admin(args) : isLoggedIn; + results.canAccessAdmin = userCollectionConfig.access.admin ? userCollectionConfig.access.admin(args) : isLoggedIn; } else { results.canAccessAdmin = false; } @@ -91,4 +91,4 @@ const policies = async (args) => { return results; }; -module.exports = policies; +module.exports = access; diff --git a/src/auth/operations/index.js b/src/auth/operations/index.js index 7d7fafd05..0abb26674 100644 --- a/src/auth/operations/index.js +++ b/src/auth/operations/index.js @@ -6,7 +6,7 @@ const forgotPassword = require('./forgotPassword'); const resetPassword = require('./resetPassword'); const registerFirstUser = require('./registerFirstUser'); const update = require('./update'); -const policies = require('./policies'); +const access = require('./access'); const me = require('./me'); module.exports = { @@ -18,6 +18,6 @@ module.exports = { update, resetPassword, registerFirstUser, - policies, + access, me, }; diff --git a/src/auth/operations/register.js b/src/auth/operations/register.js index 23e08aa55..265e5d0ed 100644 --- a/src/auth/operations/register.js +++ b/src/auth/operations/register.js @@ -1,14 +1,14 @@ const passport = require('passport'); -const executePolicy = require('../executePolicy'); +const executeStatic = require('../executeAccess'); const performFieldOperations = require('../../fields/performFieldOperations'); const register = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// if (!args.overridePolicy) { - await executePolicy(args, args.collection.config.policies.create); + await executeStatic(args, args.collection.config.access.create); } let options = { ...args }; @@ -24,7 +24,7 @@ const register = async (args) => { } // ///////////////////////////////////// - // 3. Execute field-level hooks, policies, and validation + // 3. Execute field-level hooks, access, and validation // ///////////////////////////////////// options.data = await performFieldOperations(args.collection.config, { ...options, hook: 'beforeCreate', operationName: 'create' }); @@ -62,7 +62,7 @@ const register = async (args) => { result = result.toJSON({ virtuals: true }); // ///////////////////////////////////// - // 7. Execute field-level hooks and policies + // 7. Execute field-level hooks and access // ///////////////////////////////////// result = await performFieldOperations(args.collection.config, { diff --git a/src/auth/operations/update.js b/src/auth/operations/update.js index 8cbab9312..b47c8d48a 100644 --- a/src/auth/operations/update.js +++ b/src/auth/operations/update.js @@ -1,15 +1,15 @@ const deepmerge = require('deepmerge'); const overwriteMerge = require('../../utilities/overwriteMerge'); const { NotFound, Forbidden } = require('../../errors'); -const executePolicy = require('../executePolicy'); +const executeStatic = require('../executeAccess'); const performFieldOperations = require('../../fields/performFieldOperations'); const update = async (args) => { // ///////////////////////////////////// - // 1. Execute policy + // 1. Execute access // ///////////////////////////////////// - const policyResults = await executePolicy(args, args.config.policies.update); + const policyResults = await executeStatic(args, args.config.access.update); const hasWherePolicy = typeof policyResults === 'object'; let options = { ...args }; @@ -64,7 +64,7 @@ const update = async (args) => { options.data = deepmerge(userJSON, options.data, { arrayMerge: overwriteMerge }); // ///////////////////////////////////// - // 4. Execute field-level hooks, policies, and validation + // 4. Execute field-level hooks, access, and validation // ///////////////////////////////////// options.data = await performFieldOperations(args.config, { ...options, hook: 'beforeUpdate', operationName: 'update' }); @@ -92,7 +92,7 @@ const update = async (args) => { user = user.toJSON({ virtuals: true }); // ///////////////////////////////////// - // 7. Execute field-level hooks and policies + // 7. Execute field-level hooks and access // ///////////////////////////////////// user = performFieldOperations(args.config, { diff --git a/src/auth/requestHandlers/policies.js b/src/auth/requestHandlers/access.js similarity index 76% rename from src/auth/requestHandlers/policies.js rename to src/auth/requestHandlers/access.js index 22dbdd38a..bdf71b912 100644 --- a/src/auth/requestHandlers/policies.js +++ b/src/auth/requestHandlers/access.js @@ -1,9 +1,9 @@ const httpStatus = require('http-status'); -const { policies } = require('../operations'); +const { access } = require('../operations'); const policiesHandler = config => async (req, res, next) => { try { - const policyResults = await policies({ + const policyResults = await access({ req, config, }); diff --git a/src/auth/requestHandlers/index.js b/src/auth/requestHandlers/index.js index ceaee4312..96ce73a39 100644 --- a/src/auth/requestHandlers/index.js +++ b/src/auth/requestHandlers/index.js @@ -7,7 +7,7 @@ const forgotPassword = require('./forgotPassword'); const resetPassword = require('./resetPassword'); const registerFirstUser = require('./registerFirstUser'); const update = require('./update'); -const policies = require('./policies'); +const access = require('./access'); const logout = require('./logout'); module.exports = { @@ -21,5 +21,5 @@ module.exports = { registerFirstUser, resetPassword, update, - policies, + access, }; diff --git a/src/client/components/data/User.js b/src/client/components/data/User.js index cd37e5428..b0fd17076 100644 --- a/src/client/components/data/User.js +++ b/src/client/components/data/User.js @@ -86,10 +86,10 @@ const UserProvider = ({ children }) => { setLastLocationChange(Date.now()); }, [pathname]); - // When user changes, get new policies + // When user changes, get new access useEffect(() => { async function getPermissions() { - const request = await requests.get(`${serverURL}${api}/policies`); + const request = await requests.get(`${serverURL}${api}/access`); if (request.status === 200) { const json = await request.json(); diff --git a/src/collections/operations/create.js b/src/collections/operations/create.js index 81872c980..b5360a3a3 100644 --- a/src/collections/operations/create.js +++ b/src/collections/operations/create.js @@ -1,6 +1,6 @@ const mkdirp = require('mkdirp'); -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const { MissingFile } = require('../../errors'); const resizeAndSave = require('../../uploads/imageResizer'); @@ -12,10 +12,10 @@ const performFieldOperations = require('../../fields/performFieldOperations'); const create = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// - await executePolicy(args, args.config.policies.create); + await executeStatic(args, args.config.access.create); let options = { ...args }; @@ -30,7 +30,7 @@ const create = async (args) => { } // ///////////////////////////////////// - // 3. Execute field-level policies, hooks, and validation + // 3. Execute field-level access, hooks, and validation // ///////////////////////////////////// options.data = await performFieldOperations(args.config, { ...options, hook: 'beforeCreate', operationName: 'create' }); @@ -99,7 +99,7 @@ const create = async (args) => { result = result.toJSON({ virtuals: true }); // ///////////////////////////////////// - // 6. Execute field-level hooks and policies + // 6. Execute field-level hooks and access // ///////////////////////////////////// result = await performFieldOperations(args.config, { diff --git a/src/collections/operations/delete.js b/src/collections/operations/delete.js index 5fef9691c..62d7960fb 100644 --- a/src/collections/operations/delete.js +++ b/src/collections/operations/delete.js @@ -1,13 +1,13 @@ const fs = require('fs'); const { NotFound, Forbidden, ErrorDeletingFile } = require('../../errors'); -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const deleteQuery = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// - const policyResults = await executePolicy(args, args.config.policies.delete); + const policyResults = await executeStatic(args, args.config.access.delete); const hasWherePolicy = typeof policyResults === 'object'; let options = { diff --git a/src/collections/operations/find.js b/src/collections/operations/find.js index 23a4e8e4c..c134e371c 100644 --- a/src/collections/operations/find.js +++ b/src/collections/operations/find.js @@ -1,12 +1,12 @@ -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const performFieldOperations = require('../../fields/performFieldOperations'); const find = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// - const policyResults = await executePolicy(args, args.config.policies.read); + const policyResults = await executeStatic(args, args.config.access.read); const hasWherePolicy = typeof policyResults === 'object'; const queryToBuild = {}; @@ -96,7 +96,7 @@ const find = async (args) => { let result = await Model.paginate(query, optionsToExecute); // ///////////////////////////////////// - // 4. Execute field-level policies + // 4. Execute field-level access // ///////////////////////////////////// result = { diff --git a/src/collections/operations/findByID.js b/src/collections/operations/findByID.js index 0e7753719..338beaf1e 100644 --- a/src/collections/operations/findByID.js +++ b/src/collections/operations/findByID.js @@ -1,13 +1,13 @@ const { Forbidden, NotFound } = require('../../errors'); -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const performFieldOperations = require('../../fields/performFieldOperations'); const findByID = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// - const policyResults = await executePolicy(args, args.config.policies.read); + const policyResults = await executeStatic(args, args.config.access.read); const hasWherePolicy = typeof policyResults === 'object'; const queryToBuild = { @@ -85,7 +85,7 @@ const findByID = async (args) => { result = result.toJSON({ virtuals: true }); // ///////////////////////////////////// - // 4. Execute field-level hooks and policies + // 4. Execute field-level hooks and access // ///////////////////////////////////// result = await performFieldOperations(args.config, { diff --git a/src/collections/operations/update.js b/src/collections/operations/update.js index e3c558675..cc0558b67 100644 --- a/src/collections/operations/update.js +++ b/src/collections/operations/update.js @@ -1,6 +1,6 @@ const deepmerge = require('deepmerge'); const overwriteMerge = require('../../utilities/overwriteMerge'); -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const { NotFound, Forbidden } = require('../../errors'); const performFieldOperations = require('../../fields/performFieldOperations'); const imageMIMETypes = require('../../uploads/imageMIMETypes'); @@ -11,10 +11,10 @@ const resizeAndSave = require('../../uploads/imageResizer'); const update = async (args) => { // ///////////////////////////////////// - // 1. Execute policy + // 1. Execute access // ///////////////////////////////////// - const policyResults = await executePolicy(args, args.config.policies.update); + const policyResults = await executeStatic(args, args.config.access.update); const hasWherePolicy = typeof policyResults === 'object'; let options = { ...args }; @@ -78,7 +78,7 @@ const update = async (args) => { options.data = deepmerge(options.originalDoc, options.data, { arrayMerge: overwriteMerge }); // ///////////////////////////////////// - // 4. Execute field-level hooks, policies, and validation + // 4. Execute field-level hooks, access, and validation // ///////////////////////////////////// options.data = await performFieldOperations(args.config, { ...options, hook: 'beforeUpdate', operationName: 'update' }); @@ -135,7 +135,7 @@ const update = async (args) => { doc = doc.toJSON({ virtuals: true }); // ///////////////////////////////////// - // 7. Execute field-level hooks and policies + // 7. Execute field-level hooks and access // ///////////////////////////////////// doc = await performFieldOperations(args.config, { diff --git a/src/collections/sanitize.js b/src/collections/sanitize.js index a08c6d2ef..e13c7e465 100644 --- a/src/collections/sanitize.js +++ b/src/collections/sanitize.js @@ -28,7 +28,7 @@ const sanitizeCollection = (collections, collection) => { // ///////////////////////////////// if (!sanitizedCollectionConfig.hooks) sanitizedCollectionConfig.hooks = {}; - if (!sanitizedCollectionConfig.policies) sanitizedCollectionConfig.policies = {}; + if (!sanitizedCollectionConfig.access) sanitizedCollectionConfig.access = {}; if (sanitizedCollectionConfig.upload) { if (!sanitizedCollectionConfig.upload.staticDir) sanitizedCollectionConfig.upload.staticDir = sanitizedCollectionConfig.slug; diff --git a/src/express/static.js b/src/express/static.js index 7f9562d73..67fa847ae 100644 --- a/src/express/static.js +++ b/src/express/static.js @@ -1,6 +1,6 @@ const express = require('express'); const passport = require('passport'); -const getExecuteStaticPolicy = require('../auth/getExecuteStaticPolicy'); +const getExecuteStaticAccess = require('../auth/getExecuteStaticAccess'); const authenticate = require('./middleware/authenticate'); function initStatic() { @@ -13,7 +13,7 @@ function initStatic() { router.use(passport.initialize()); router.use(authenticate(this.config)); - router.use(getExecuteStaticPolicy(collection)); + router.use(getExecuteStaticAccess(collection)); router.use(express.static(config.upload.staticDir)); this.express.use(`${config.upload.staticURL}`, router); diff --git a/src/fields/performFieldOperations.js b/src/fields/performFieldOperations.js index 5d5b2fc64..82f4e6e59 100644 --- a/src/fields/performFieldOperations.js +++ b/src/fields/performFieldOperations.js @@ -9,7 +9,7 @@ module.exports = async (config, operation) => { } = operation; // Maintain a top-level list of promises - // so that all async field policies / validations / hooks + // so that all async field access / validations / hooks // can run in parallel const validationPromises = []; const policyPromises = []; @@ -32,8 +32,8 @@ module.exports = async (config, operation) => { const createPolicyPromise = async (data, originalDoc, field) => { const resultingData = data; - if (field.policies && field.policies[operationName]) { - const result = await field.policies[operationName](operation); + if (field.access && field.access[operationName]) { + const result = await field.access[operationName](operation); if (!result && operationName === 'update' && originalDoc[field.name] !== undefined) { resultingData[field.name] = originalDoc[field.name]; diff --git a/src/fields/sanitize.js b/src/fields/sanitize.js index fe0152d08..dd522aa12 100644 --- a/src/fields/sanitize.js +++ b/src/fields/sanitize.js @@ -1,5 +1,5 @@ const { MissingFieldType } = require('../errors'); -const validations = require('../fields/validations'); +const validations = require('./validations'); const sanitizeFields = (fields) => { if (!fields) return []; @@ -16,7 +16,7 @@ const sanitizeFields = (fields) => { } if (!field.hooks) field.hooks = {}; - if (!field.policies) field.policies = {}; + if (!field.access) field.access = {}; if (field.fields) field.fields = sanitizeFields(field.fields); diff --git a/src/globals/operations/findOne.js b/src/globals/operations/findOne.js index b89ec251c..f11b85fdd 100644 --- a/src/globals/operations/findOne.js +++ b/src/globals/operations/findOne.js @@ -1,12 +1,12 @@ -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const performFieldOperations = require('../../fields/performFieldOperations'); const findOne = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// - await executePolicy(args, args.config.policies.read); + await executeStatic(args, args.config.access.read); let options = { ...args }; @@ -67,7 +67,7 @@ const findOne = async (args) => { // ///////////////////////////////////// - // 4. Execute field-level hooks and policies + // 4. Execute field-level hooks and access // ///////////////////////////////////// result = performFieldOperations(args.config, { diff --git a/src/globals/operations/update.js b/src/globals/operations/update.js index 7a0828c2f..9c6294a15 100644 --- a/src/globals/operations/update.js +++ b/src/globals/operations/update.js @@ -1,14 +1,14 @@ const deepmerge = require('deepmerge'); const overwriteMerge = require('../../utilities/overwriteMerge'); -const executePolicy = require('../../auth/executePolicy'); +const executeStatic = require('../../auth/executeAccess'); const performFieldOperations = require('../../fields/performFieldOperations'); const update = async (args) => { // ///////////////////////////////////// - // 1. Retrieve and execute policy + // 1. Retrieve and execute access // ///////////////////////////////////// - await executePolicy(args, args.config.policies.update); + await executeStatic(args, args.config.access.update); let options = { ...args }; @@ -54,7 +54,7 @@ const update = async (args) => { options.data = deepmerge(globalJSON, options.data, { arrayMerge: overwriteMerge }); // ///////////////////////////////////// - // 5. Execute field-level hooks, policies, and validation + // 5. Execute field-level hooks, access, and validation // ///////////////////////////////////// options.data = await performFieldOperations(args.config, { ...options, hook: 'beforeUpdate', operationName: 'update' }); @@ -70,7 +70,7 @@ const update = async (args) => { global = global.toJSON({ virtuals: true }); // ///////////////////////////////////// - // 7. Execute field-level hooks and policies + // 7. Execute field-level hooks and access // ///////////////////////////////////// global = await performFieldOperations(args.config, { diff --git a/src/globals/sanitize.js b/src/globals/sanitize.js index bd48038f5..852b98e0c 100644 --- a/src/globals/sanitize.js +++ b/src/globals/sanitize.js @@ -20,7 +20,7 @@ const sanitizeGlobals = (globals) => { // ///////////////////////////////// if (!sanitizedGlobal.hooks) sanitizedGlobal.hooks = {}; - if (!sanitizedGlobal.policies) sanitizedGlobal.policies = {}; + if (!sanitizedGlobal.access) sanitizedGlobal.access = {}; // ///////////////////////////////// // Sanitize fields diff --git a/src/graphql/index.js b/src/graphql/index.js index 18a4a5322..d5f4256f5 100644 --- a/src/graphql/index.js +++ b/src/graphql/index.js @@ -11,7 +11,7 @@ const initCollections = require('../collections/graphql/init'); const initGlobals = require('../globals/graphql/init'); const buildWhereInputType = require('./schema/buildWhereInputType'); const errorHandler = require('./errorHandler'); -const { policies } = require('../auth/graphql/resolvers'); +const { access } = require('../auth/graphql/resolvers'); class GraphQL { constructor(init) { @@ -50,9 +50,9 @@ class GraphQL { this.initCollections(); this.initGlobals(); - this.Query.fields.Policies = { + this.Query.fields.Access = { type: this.buildPoliciesType(), - resolve: policies(this.config), + resolve: access(this.config), }; this.Query = { diff --git a/src/graphql/schema/buildPoliciesType.js b/src/graphql/schema/buildPoliciesType.js index 90a90ed00..6f6633731 100644 --- a/src/graphql/schema/buildPoliciesType.js +++ b/src/graphql/schema/buildPoliciesType.js @@ -2,61 +2,59 @@ const { GraphQLJSONObject } = require('graphql-type-json'); const { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType } = require('graphql'); const formatName = require('../utilities/formatName'); -const buildFields = (label, fieldsToBuild) => { - return fieldsToBuild.reduce((builtFields, field) => { - if (field.name) { - const fieldName = formatName(field.name); +const buildFields = (label, fieldsToBuild) => fieldsToBuild.reduce((builtFields, field) => { + if (field.name) { + const fieldName = formatName(field.name); - const objectTypeFields = ['create', 'read', 'update', 'delete'].reduce((operations, operation) => { - const capitalizedOperation = operation.charAt(0).toUpperCase() + operation.slice(1); - - return { - ...operations, - [operation]: { - type: new GraphQLObjectType({ - name: `${label}_${fieldName}_${capitalizedOperation}`, - fields: { - permission: { - type: new GraphQLNonNull(GraphQLBoolean), - }, - }, - }), - }, - }; - }, {}); - - if (field.fields) { - objectTypeFields.fields = { - type: new GraphQLObjectType({ - name: `${label}_${fieldName}_Fields`, - fields: buildFields(`${label}_${fieldName}`, field.fields), - }), - }; - } + const objectTypeFields = ['create', 'read', 'update', 'delete'].reduce((operations, operation) => { + const capitalizedOperation = operation.charAt(0).toUpperCase() + operation.slice(1); return { - ...builtFields, - [field.name]: { + ...operations, + [operation]: { type: new GraphQLObjectType({ - name: `${label}_${fieldName}`, - fields: objectTypeFields, + name: `${label}_${fieldName}_${capitalizedOperation}`, + fields: { + permission: { + type: new GraphQLNonNull(GraphQLBoolean), + }, + }, }), }, }; - } + }, {}); - if (!field.name && field.fields) { - const subFields = buildFields(label, field.fields); - - return { - ...builtFields, - ...subFields, + if (field.fields) { + objectTypeFields.fields = { + type: new GraphQLObjectType({ + name: `${label}_${fieldName}_Fields`, + fields: buildFields(`${label}_${fieldName}`, field.fields), + }), }; } - return builtFields; - }, {}); -}; + return { + ...builtFields, + [field.name]: { + type: new GraphQLObjectType({ + name: `${label}_${fieldName}`, + fields: objectTypeFields, + }), + }, + }; + } + + if (!field.name && field.fields) { + const subFields = buildFields(label, field.fields); + + return { + ...builtFields, + ...subFields, + }; + } + + return builtFields; +}, {}); const buildEntity = (label, entityFields, operations) => { const formattedLabel = formatName(label); @@ -75,7 +73,7 @@ const buildEntity = (label, entityFields, operations) => { fields[operation] = { type: new GraphQLObjectType({ - name: `${formattedLabel}${capitalizedOperation}Policy`, + name: `${formattedLabel}${capitalizedOperation}Access`, fields: { permission: { type: new GraphQLNonNull(GraphQLBoolean) }, where: { type: GraphQLJSONObject }, @@ -97,7 +95,7 @@ function buildPoliciesType() { Object.values(this.config.collections).forEach((collection) => { fields[formatName(collection.slug)] = { type: new GraphQLObjectType({ - name: formatName(`${collection.labels.singular}Policy`), + name: formatName(`${collection.labels.singular}Access`), fields: buildEntity(collection.labels.singular, collection.fields, ['create', 'read', 'update', 'delete']), }), }; @@ -106,14 +104,14 @@ function buildPoliciesType() { Object.values(this.config.globals).forEach((global) => { fields[formatName(global.slug)] = { type: new GraphQLObjectType({ - name: formatName(`${global.label}Policy`), + name: formatName(`${global.label}Access`), fields: buildEntity(global.label, global.fields, ['read', 'update']), }), }; }); return new GraphQLObjectType({ - name: 'Policies', + name: 'Access', fields, }); } diff --git a/src/index.js b/src/index.js index 98bc3f74f..87f25206a 100644 --- a/src/index.js +++ b/src/index.js @@ -17,7 +17,7 @@ const sanitizeConfig = require('./utilities/sanitizeConfig'); const buildEmail = require('./email/build'); const identifyAPI = require('./express/middleware/identifyAPI'); const errorHandler = require('./express/middleware/errorHandler'); -const { policies } = require('./auth/requestHandlers'); +const { access } = require('./auth/requestHandlers'); class Payload { constructor(options) { @@ -53,7 +53,7 @@ class Payload { this.initGlobals(); this.initAdmin(); - this.router.get('/policies', policies(this.config)); + this.router.get('/access', access(this.config)); this.router.use( this.config.routes.graphQL, diff --git a/src/mongoose/buildSchema.js b/src/mongoose/buildSchema.js index 115db7b76..480971ef7 100644 --- a/src/mongoose/buildSchema.js +++ b/src/mongoose/buildSchema.js @@ -3,7 +3,7 @@ const { Schema } = require('mongoose'); const { MissingSelectOptions } = require('../errors'); const formatBaseSchema = (field) => { - const createPolicy = field.policies && field.policies.create; + const createPolicy = field.access && field.access.create; return { hide: field.hidden === 'api' || field.hidden === true, @@ -49,71 +49,51 @@ const buildSchema = (configFields, options = {}) => { }; const fieldToSchemaMap = { - number: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: Number }, - }; - }, - text: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: String }, - }; - }, - email: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: String }, - }; - }, - textarea: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: String }, - }; - }, - richText: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: Schema.Types.Mixed }, - }; - }, - code: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: String }, - }; - }, - radio: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: String }, - }; - }, - checkbox: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: Boolean }, - }; - }, - date: (field, fields) => { - return { - ...fields, - [field.name]: { ...formatBaseSchema(field), type: Date }, - }; - }, - upload: (field, fields) => { - return { - ...fields, - [field.name]: { - ...formatBaseSchema(field), - type: Schema.Types.ObjectId, - autopopulate: true, - ref: field.relationTo, - }, - }; - }, + number: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: Number }, + }), + text: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: String }, + }), + email: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: String }, + }), + textarea: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: String }, + }), + richText: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: Schema.Types.Mixed }, + }), + code: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: String }, + }), + radio: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: String }, + }), + checkbox: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: Boolean }, + }), + date: (field, fields) => ({ + ...fields, + [field.name]: { ...formatBaseSchema(field), type: Date }, + }), + upload: (field, fields) => ({ + ...fields, + [field.name]: { + ...formatBaseSchema(field), + type: Schema.Types.ObjectId, + autopopulate: true, + ref: field.relationTo, + }, + }), relationship: (field, fields) => { let schema = {}; @@ -178,7 +158,7 @@ const fieldToSchemaMap = { ...fields, [field.name]: { ...formatBaseSchema(field), - required: field.fields.some(subField => subField.required === true), + required: field.fields.some((subField) => subField.required === true), type: schema, }, };