| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- const { expressify } = require('../../util/promises')
- const async = require('async')
- const UserMembershipAuthorization = require('./UserMembershipAuthorization')
- const AuthenticationController = require('../Authentication/AuthenticationController')
- const UserMembershipHandler = require('./UserMembershipHandler')
- const EntityConfigs = require('./UserMembershipEntityConfigs')
- const Errors = require('../Errors/Errors')
- const HttpErrorHandler = require('../Errors/HttpErrorHandler')
- const TemplatesManager = require('../Templates/TemplatesManager')
- // set of middleware arrays or functions that checks user access to an entity
- // (publisher, institution, group, template, etc.)
- const UserMembershipMiddleware = {
- requireTeamMetricsAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('team'),
- fetchEntity(),
- requireEntity(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('groupMetrics'),
- ]),
- ],
- requireGroupManagementAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('group'),
- fetchEntity(),
- requireEntity(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('groupManagement'),
- ]),
- ],
- requireGroupMetricsAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('group'),
- fetchEntity(),
- requireEntity(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('groupMetrics'),
- ]),
- ],
- requireGroupManagersManagementAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('groupManagers'),
- fetchEntity(),
- requireEntity(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('groupManagement'),
- ]),
- ],
- requireInstitutionMetricsAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('institution'),
- fetchEntity(),
- requireEntityOrCreate('institutionManagement'),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('institutionMetrics'),
- ]),
- ],
- requireInstitutionManagementAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('institution'),
- fetchEntity(),
- requireEntityOrCreate('institutionManagement'),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('institutionManagement'),
- ]),
- ],
- requireInstitutionManagementStaffAccess: [
- AuthenticationController.requireLogin(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasStaffAccess('institutionManagement'),
- ]),
- fetchEntityConfig('institution'),
- fetchEntity(),
- requireEntityOrCreate('institutionManagement'),
- ],
- requirePublisherMetricsAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('publisher'),
- fetchEntity(),
- requireEntityOrCreate('publisherManagement'),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('publisherMetrics'),
- ]),
- ],
- requirePublisherManagementAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('publisher'),
- fetchEntity(),
- requireEntityOrCreate('publisherManagement'),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('publisherManagement'),
- ]),
- ],
- requireConversionMetricsAccess: [
- AuthenticationController.requireLogin(),
- fetchEntityConfig('publisher'),
- fetchEntity(),
- requireEntityOrCreate('publisherManagement'),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('publisherMetrics'),
- ]),
- ],
- requireAdminMetricsAccess: [
- AuthenticationController.requireLogin(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasStaffAccess('adminMetrics'),
- ]),
- ],
- requireTemplateMetricsAccess: [
- AuthenticationController.requireLogin(),
- fetchV1Template(),
- requireV1Template(),
- fetchEntityConfig('publisher'),
- fetchPublisherFromTemplate(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasEntityAccess(),
- UserMembershipAuthorization.hasStaffAccess('publisherMetrics'),
- ]),
- ],
- requirePublisherCreationAccess: [
- AuthenticationController.requireLogin(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasStaffAccess('publisherManagement'),
- ]),
- fetchEntityConfig('publisher'),
- ],
- requireInstitutionCreationAccess: [
- AuthenticationController.requireLogin(),
- allowAccessIfAny([
- UserMembershipAuthorization.hasStaffAccess('institutionManagement'),
- ]),
- fetchEntityConfig('institution'),
- ],
- // graphs access is an edge-case:
- // - the entity id is in `req.query.resource_id`. It must be set as
- // `req.params.id`
- // - the entity name is in `req.query.resource_type` and is used to find the
- // require middleware depending on the entity name
- requireGraphAccess(req, res, next) {
- req.params.id = req.query.resource_id
- let entityName = req.query.resource_type
- if (!entityName) {
- return HttpErrorHandler.notFound(req, res, 'resource_type param missing')
- }
- entityName = entityName.charAt(0).toUpperCase() + entityName.slice(1)
- const middleware =
- UserMembershipMiddleware[`require${entityName}MetricsAccess`]
- if (!middleware) {
- return HttpErrorHandler.notFound(
- req,
- res,
- `incorrect entity name: ${entityName}`
- )
- }
- // run the list of middleware functions in series. This is essencially
- // a poor man's middleware runner
- async.eachSeries(middleware, (fn, callback) => fn(req, res, callback), next)
- },
- }
- module.exports = UserMembershipMiddleware
- // fetch entity config and set it in the request
- function fetchEntityConfig(entityName) {
- return (req, res, next) => {
- const entityConfig = EntityConfigs[entityName]
- req.entityName = entityName
- req.entityConfig = entityConfig
- next()
- }
- }
- // fetch the entity with id and config, and set it in the request
- function fetchEntity() {
- return expressify(async (req, res, next) => {
- const entity =
- await UserMembershipHandler.promises.getEntityWithoutAuthorizationCheck(
- req.params.id,
- req.entityConfig
- )
- req.entity = entity
- next()
- })
- }
- function fetchPublisherFromTemplate() {
- return (req, res, next) => {
- if (req.template.brand.slug) {
- // set the id as the publisher's id as it's the entity used for access
- // control
- req.params.id = req.template.brand.slug
- return fetchEntity()(req, res, next)
- } else {
- return next()
- }
- }
- }
- // ensure an entity was found, or fail with 404
- function requireEntity() {
- return (req, res, next) => {
- if (req.entity) {
- return next()
- }
- throw new Errors.NotFoundError(
- `no '${req.entityName}' entity with '${req.params.id}'`
- )
- }
- }
- // ensure an entity was found or redirect to entity creation page if the user
- // has permissions to create the entity, or fail with 404
- function requireEntityOrCreate(creationStaffAccess) {
- return (req, res, next) => {
- if (req.entity) {
- return next()
- }
- if (UserMembershipAuthorization.hasStaffAccess(creationStaffAccess)(req)) {
- res.redirect(`/entities/${req.entityName}/create/${req.params.id}`)
- return
- }
- throw new Errors.NotFoundError(
- `no '${req.entityName}' entity with '${req.params.id}'`
- )
- }
- }
- // fetch the template from v1, and set it in the request
- function fetchV1Template() {
- return expressify(async (req, res, next) => {
- const templateId = req.params.id
- const body = await TemplatesManager.promises.fetchFromV1(templateId)
- req.template = {
- id: body.id,
- title: body.title,
- brand: body.brand,
- }
- next()
- })
- }
- // ensure a template was found, or fail with 404
- function requireV1Template() {
- return (req, res, next) => {
- if (req.template.id) {
- return next()
- }
- throw new Errors.NotFoundError('no template found')
- }
- }
- // run a serie of synchronous access functions and call `next` if any of the
- // retur values is truly. Redirect to restricted otherwise
- function allowAccessIfAny(accessFunctions) {
- return (req, res, next) => {
- for (const accessFunction of accessFunctions) {
- if (accessFunction(req)) {
- return next()
- }
- }
- HttpErrorHandler.forbidden(req, res)
- }
- }
|