{"version":3,"file":"index.mjs","sources":["../../../../src/services/content-api/permissions/index.ts"],"sourcesContent":["import _ from 'lodash';\nimport type { Core } from '@strapi/types';\nimport { createActionProvider, createConditionProvider } from './providers';\nimport createPermissionEngine from './engine';\n\nconst typeSymbol = Symbol.for('__type__');\n\ninterface ValidatePermissionHandler {\n  (params: { permission: { action: string } }): boolean;\n}\n\n/**\n * Creates a handler that checks if the permission's action exists in the action registry\n */\nconst createValidatePermissionHandler =\n  (actionProvider: ReturnType<typeof createActionProvider>): ValidatePermissionHandler =>\n  ({ permission }) => {\n    const action = actionProvider.get(permission.action);\n\n    // If the action isn't registered into the action provider, then ignore the permission and warn the user\n    if (!action) {\n      strapi.log.debug(\n        `Unknown action \"${permission.action}\" supplied when registering a new permission`\n      );\n\n      return false;\n    }\n\n    return true;\n  };\n\n/**\n * Create instances of providers and permission engine for the core content-API service.\n * Also, expose utilities to get information about available actions and such.\n */\nexport default (strapi: Core.Strapi) => {\n  // NOTE: Here we define both an action and condition provider,\n  // but at the moment, we're only using the action one.\n  const providers = {\n    action: createActionProvider(),\n    condition: createConditionProvider(),\n  };\n\n  /**\n   * Get a tree representation of the available Content API actions\n   * based on the methods of the Content API controllers.\n   *\n   * @note Only actions bound to a content-API route are returned.\n   */\n  const getActionsMap = () => {\n    const actionMap: Record<\n      string,\n      {\n        controllers: Record<string, string[]>;\n      }\n    > = {};\n\n    /**\n     * Check if a controller's action is bound to the\n     * content-api by looking at a potential __type__ symbol\n     */\n    const isContentApi = (action: Core.ControllerHandler & { [s: symbol]: any }) => {\n      if (!_.has(action, typeSymbol)) {\n        return false;\n      }\n\n      return action[typeSymbol].includes('content-api');\n    };\n\n    /**\n     * Register actions from a specific API source into the result tree\n     */\n    const registerAPIsActions = (\n      apis: Record<string, Core.Plugin | Core.Module>,\n      source: 'api' | 'plugin'\n    ) => {\n      _.forEach(apis, (api, apiName) => {\n        const controllers = _.reduce(\n          api.controllers,\n          (acc, controller, controllerName) => {\n            const contentApiActions = _.pickBy(controller, isContentApi);\n\n            if (_.isEmpty(contentApiActions)) {\n              return acc;\n            }\n\n            acc[controllerName] = Object.keys(contentApiActions);\n\n            return acc;\n          },\n          {} as Record<string, string[]>\n        );\n\n        if (!_.isEmpty(controllers)) {\n          actionMap[`${source}::${apiName}`] = { controllers };\n        }\n      });\n    };\n\n    registerAPIsActions(strapi.apis, 'api');\n    registerAPIsActions(strapi.plugins, 'plugin');\n\n    return actionMap;\n  };\n\n  /**\n   * Register all the content-API controllers actions into the action provider.\n   * This method make use of the {@link getActionsMap} to generate the list of actions to register.\n   */\n  const registerActions = async () => {\n    const actionsMap = getActionsMap();\n\n    // For each API\n    for (const [api, value] of Object.entries(actionsMap)) {\n      const { controllers } = value;\n\n      // Register controllers methods as actions\n      for (const [controller, actions] of Object.entries(controllers)) {\n        // Register each action individually\n        await Promise.all(\n          actions.map((action) => {\n            const actionUID = `${api}.${controller}.${action}`;\n\n            return providers.action.register(actionUID, {\n              api,\n              controller,\n              action,\n              uid: actionUID,\n            });\n          })\n        );\n      }\n    }\n  };\n\n  // Create an instance of a content-API permission engine\n  // and binds a custom validation handler to it\n  const engine = createPermissionEngine({ providers });\n\n  engine.on(\n    'before-format::validate.permission',\n    createValidatePermissionHandler(providers.action)\n  );\n\n  return {\n    engine,\n    providers,\n    registerActions,\n    getActionsMap,\n  };\n};\n"],"names":["typeSymbol","Symbol","for","createValidatePermissionHandler","actionProvider","permission","action","get","strapi","log","debug","providers","createActionProvider","condition","createConditionProvider","getActionsMap","actionMap","isContentApi","_","has","includes","registerAPIsActions","apis","source","forEach","api","apiName","controllers","reduce","acc","controller","controllerName","contentApiActions","pickBy","isEmpty","Object","keys","plugins","registerActions","actionsMap","value","entries","actions","Promise","all","map","actionUID","register","uid","engine","createPermissionEngine","on"],"mappings":"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"}