2021-07-08 18:15:32 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const _ = require('lodash');
|
|
|
|
const request = require('request');
|
|
|
|
const { getService } = require('../utils');
|
|
|
|
|
|
|
|
const DEFAULT_PERMISSIONS = [
|
|
|
|
{ action: 'admincallback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
|
|
|
{ action: 'adminregister', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
|
|
|
{ action: 'callback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
|
|
|
{ action: 'connect', controller: 'auth', type: 'users-permissions', roleType: null },
|
|
|
|
{ action: 'forgotpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
|
|
|
{ action: 'register', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
|
|
|
{
|
|
|
|
action: 'emailconfirmation',
|
|
|
|
controller: 'auth',
|
|
|
|
type: 'users-permissions',
|
|
|
|
roleType: 'public',
|
|
|
|
},
|
|
|
|
{ action: 'resetpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
|
|
|
|
{ action: 'init', controller: 'userspermissions', type: null, roleType: null },
|
|
|
|
{ action: 'me', controller: 'user', type: 'users-permissions', roleType: null },
|
|
|
|
{ action: 'autoreload', controller: null, type: null, roleType: null },
|
|
|
|
];
|
|
|
|
|
|
|
|
const isPermissionEnabled = (permission, role) =>
|
|
|
|
DEFAULT_PERMISSIONS.some(
|
|
|
|
defaultPerm =>
|
|
|
|
(defaultPerm.action === null || permission.action === defaultPerm.action) &&
|
|
|
|
(defaultPerm.controller === null || permission.controller === defaultPerm.controller) &&
|
|
|
|
(defaultPerm.type === null || permission.type === defaultPerm.type) &&
|
|
|
|
(defaultPerm.roleType === null || role.type === defaultPerm.roleType)
|
|
|
|
);
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
async createRole(params) {
|
|
|
|
if (!params.type) {
|
|
|
|
params.type = _.snakeCase(_.deburr(_.toLower(params.name)));
|
|
|
|
}
|
|
|
|
|
|
|
|
const role = await strapi
|
|
|
|
.query('plugins::users-permissions.role')
|
|
|
|
.create({ data: _.omit(params, ['users', 'permissions']) });
|
|
|
|
|
|
|
|
const arrayOfPromises = Object.keys(params.permissions || {}).reduce((acc, type) => {
|
|
|
|
Object.keys(params.permissions[type].controllers).forEach(controller => {
|
|
|
|
Object.keys(params.permissions[type].controllers[controller]).forEach(action => {
|
|
|
|
acc.push(
|
|
|
|
strapi.query('plugins::users-permissions.permission').create({
|
|
|
|
data: {
|
|
|
|
role: role.id,
|
|
|
|
type,
|
|
|
|
controller,
|
|
|
|
action: action.toLowerCase(),
|
|
|
|
...params.permissions[type].controllers[controller][action],
|
|
|
|
},
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
// Use Content Manager business logic to handle relation.
|
|
|
|
if (params.users && params.users.length > 0)
|
|
|
|
arrayOfPromises.push(
|
|
|
|
strapi.query('plugins::users-permissions.role').update({
|
|
|
|
where: {
|
|
|
|
id: role.id,
|
|
|
|
},
|
|
|
|
data: { users: params.users },
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
return await Promise.all(arrayOfPromises);
|
|
|
|
},
|
|
|
|
|
|
|
|
async deleteRole(roleID, publicRoleID) {
|
|
|
|
const role = await strapi
|
|
|
|
.query('plugins::users-permissions.role')
|
|
|
|
.findOne({ where: { id: roleID }, populate: ['users', 'permissions'] });
|
|
|
|
|
|
|
|
if (!role) {
|
|
|
|
throw new Error('Cannot find this role');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move users to guest role.
|
|
|
|
const arrayOfPromises = role.users.reduce((acc, user) => {
|
|
|
|
acc.push(
|
|
|
|
strapi.query('plugins::users-permissions.user').update({
|
|
|
|
where: {
|
|
|
|
id: user.id,
|
|
|
|
},
|
|
|
|
data: {
|
|
|
|
role: publicRoleID,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
// Remove permissions related to this role.
|
|
|
|
role.permissions.forEach(permission => {
|
|
|
|
arrayOfPromises.push(
|
|
|
|
strapi.query('plugins::users-permissions.permission').delete({
|
|
|
|
where: { id: permission.id },
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Delete the role.
|
|
|
|
arrayOfPromises.push(
|
|
|
|
strapi.query('plugins::users-permissions.role').delete({ where: { id: roleID } })
|
|
|
|
);
|
|
|
|
|
|
|
|
return await Promise.all(arrayOfPromises);
|
|
|
|
},
|
|
|
|
|
|
|
|
getPlugins(lang = 'en') {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
request(
|
|
|
|
{
|
|
|
|
uri: `https://marketplace.strapi.io/plugins?lang=${lang}`,
|
|
|
|
json: true,
|
|
|
|
timeout: 3000,
|
|
|
|
headers: {
|
|
|
|
'cache-control': 'max-age=3600',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
(err, response, body) => {
|
|
|
|
if (err || response.statusCode !== 200) {
|
|
|
|
return resolve([]);
|
|
|
|
}
|
|
|
|
|
|
|
|
resolve(body);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
getActions() {
|
|
|
|
const generateActions = data =>
|
|
|
|
Object.keys(data).reduce((acc, key) => {
|
|
|
|
if (_.isFunction(data[key])) {
|
|
|
|
acc[key] = { enabled: false, policy: '' };
|
|
|
|
}
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
const appControllers = Object.keys(strapi.api || {})
|
|
|
|
.filter(key => !!strapi.api[key].controllers)
|
|
|
|
.reduce(
|
|
|
|
(acc, key) => {
|
|
|
|
Object.keys(strapi.api[key].controllers).forEach(controller => {
|
|
|
|
acc.controllers[controller] = generateActions(strapi.api[key].controllers[controller]);
|
|
|
|
});
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
},
|
|
|
|
{ controllers: {} }
|
|
|
|
);
|
|
|
|
|
|
|
|
const pluginsPermissions = Object.keys(strapi.plugins).reduce((acc, key) => {
|
|
|
|
const initialState = {
|
|
|
|
controllers: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
acc[key] = Object.keys(strapi.plugins[key].controllers).reduce((obj, k) => {
|
|
|
|
obj.controllers[k] = generateActions(strapi.plugins[key].controllers[k]);
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}, initialState);
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
const permissions = {
|
|
|
|
application: {
|
|
|
|
controllers: appControllers.controllers,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
return _.merge(permissions, pluginsPermissions);
|
|
|
|
},
|
|
|
|
|
|
|
|
async getRole(roleID, plugins) {
|
|
|
|
const role = await strapi
|
|
|
|
.query('plugins::users-permissions.role')
|
|
|
|
.findOne({ where: { id: roleID }, populate: ['permissions'] });
|
|
|
|
|
|
|
|
if (!role) {
|
|
|
|
throw new Error('Cannot find this role');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Group by `type`.
|
|
|
|
const permissions = role.permissions.reduce((acc, permission) => {
|
|
|
|
_.set(acc, `${permission.type}.controllers.${permission.controller}.${permission.action}`, {
|
|
|
|
enabled: _.toNumber(permission.enabled) == true,
|
|
|
|
policy: permission.policy,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (permission.type !== 'application' && !acc[permission.type].information) {
|
|
|
|
acc[permission.type].information =
|
|
|
|
plugins.find(plugin => plugin.id === permission.type) || {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
return {
|
|
|
|
...role,
|
|
|
|
permissions,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
async getRoles() {
|
|
|
|
const roles = await strapi
|
|
|
|
.query('plugins::users-permissions.role')
|
|
|
|
.findMany({ sort: ['name'] });
|
|
|
|
|
|
|
|
for (let i = 0; i < roles.length; ++i) {
|
|
|
|
roles[i].nb_users = await strapi
|
|
|
|
.query('plugins::users-permissions.user')
|
|
|
|
.count({ where: { role: { id: roles[i].id } } });
|
|
|
|
}
|
|
|
|
|
|
|
|
return roles;
|
|
|
|
},
|
|
|
|
|
|
|
|
async getRoutes() {
|
|
|
|
const routes = Object.keys(strapi.api || {}).reduce((acc, current) => {
|
|
|
|
return acc.concat(_.get(strapi.api[current].config, 'routes', []));
|
|
|
|
}, []);
|
|
|
|
const clonedPlugins = _.cloneDeep(strapi.plugins);
|
|
|
|
const pluginsRoutes = Object.keys(clonedPlugins || {}).reduce((acc, current) => {
|
|
|
|
const routes = _.get(clonedPlugins, [current, 'config', 'routes'], []).reduce((acc, curr) => {
|
|
|
|
const prefix = curr.config.prefix;
|
|
|
|
const path = prefix !== undefined ? `${prefix}${curr.path}` : `/${current}${curr.path}`;
|
|
|
|
_.set(curr, 'path', path);
|
|
|
|
|
|
|
|
return acc.concat(curr);
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
acc[current] = routes;
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
|
|
|
|
return _.merge({ application: routes }, pluginsRoutes);
|
|
|
|
},
|
|
|
|
|
|
|
|
async updatePermissions() {
|
|
|
|
const roles = await strapi.query('plugins::users-permissions.role').findMany();
|
|
|
|
|
|
|
|
const rolesMap = _.groupBy(roles, 'id');
|
|
|
|
|
|
|
|
const dbPermissions = await strapi
|
|
|
|
.query('plugins::users-permissions.permission')
|
|
|
|
.findMany({ populate: ['role'] });
|
|
|
|
|
|
|
|
let permissionsFoundInDB = dbPermissions.map(permission => {
|
|
|
|
const { type, controller, action, role } = permission;
|
|
|
|
return `${type}.${controller}.${action}.${role.id}`;
|
|
|
|
});
|
|
|
|
|
|
|
|
permissionsFoundInDB = _.uniq(permissionsFoundInDB);
|
|
|
|
|
|
|
|
// Aggregate first level actions.
|
|
|
|
const appActions = Object.keys(strapi.api || {}).reduce((acc, api) => {
|
|
|
|
Object.keys(_.get(strapi.api[api], 'controllers', {})).forEach(controller => {
|
|
|
|
const actions = Object.keys(strapi.api[api].controllers[controller])
|
|
|
|
.filter(action => _.isFunction(strapi.api[api].controllers[controller][action]))
|
|
|
|
.map(action => `application.${controller}.${action.toLowerCase()}`);
|
|
|
|
|
|
|
|
acc = acc.concat(actions);
|
|
|
|
});
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
// Aggregate plugins' actions.
|
|
|
|
const pluginsActions = Object.keys(strapi.plugins).reduce((acc, plugin) => {
|
|
|
|
Object.keys(strapi.plugins[plugin].controllers).forEach(controller => {
|
|
|
|
const actions = Object.keys(strapi.plugins[plugin].controllers[controller])
|
|
|
|
.filter(action => _.isFunction(strapi.plugins[plugin].controllers[controller][action]))
|
|
|
|
.map(action => `${plugin}.${controller}.${action.toLowerCase()}`);
|
|
|
|
|
|
|
|
acc = acc.concat(actions);
|
|
|
|
});
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const actionsFoundInFiles = appActions.concat(pluginsActions);
|
|
|
|
|
|
|
|
const permissionsFoundInFiles = [];
|
|
|
|
|
|
|
|
for (const role of roles) {
|
|
|
|
actionsFoundInFiles.forEach(action => {
|
|
|
|
permissionsFoundInFiles.push(`${action}.${role.id}`);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compare to know if actions have been added or removed from controllers.
|
|
|
|
if (!_.isEqual(permissionsFoundInDB.sort(), permissionsFoundInFiles.sort())) {
|
|
|
|
const splitted = str => {
|
|
|
|
const [type, controller, action, roleId] = str.split('.');
|
|
|
|
|
|
|
|
return { type, controller, action, roleId };
|
|
|
|
};
|
|
|
|
|
|
|
|
// We have to know the difference to add or remove the permissions entries in the database.
|
|
|
|
const toRemove = _.difference(permissionsFoundInDB, permissionsFoundInFiles).map(splitted);
|
|
|
|
const toAdd = _.difference(permissionsFoundInFiles, permissionsFoundInDB).map(splitted);
|
|
|
|
|
|
|
|
const query = strapi.query('plugins::users-permissions.permission');
|
|
|
|
|
|
|
|
// Execute request to update entries in database for each role.
|
|
|
|
await Promise.all(
|
|
|
|
toAdd.map(permission =>
|
|
|
|
query.create({
|
|
|
|
data: {
|
|
|
|
type: permission.type,
|
|
|
|
controller: permission.controller,
|
|
|
|
action: permission.action,
|
|
|
|
enabled: isPermissionEnabled(permission, rolesMap[permission.roleId]),
|
|
|
|
policy: '',
|
|
|
|
role: permission.roleId,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
await Promise.all(
|
|
|
|
toRemove.map(permission => {
|
|
|
|
const { type, controller, action, roleId } = permission;
|
|
|
|
return query.delete({ where: { type, controller, action, role: { id: roleId } } });
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
async initialize() {
|
|
|
|
const roleCount = await strapi.query('plugins::users-permissions.role').count();
|
|
|
|
|
|
|
|
if (roleCount === 0) {
|
|
|
|
await strapi.query('plugins::users-permissions.role').create({
|
|
|
|
data: {
|
|
|
|
name: 'Authenticated',
|
|
|
|
description: 'Default role given to authenticated user.',
|
|
|
|
type: 'authenticated',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
await strapi.query('plugins::users-permissions.role').create({
|
|
|
|
data: {
|
|
|
|
name: 'Public',
|
|
|
|
description: 'Default role given to unauthenticated user.',
|
|
|
|
type: 'public',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-07-08 21:53:30 +02:00
|
|
|
return getService('users-permissions').updatePermissions();
|
2021-07-08 18:15:32 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
async updateRole(roleID, body) {
|
|
|
|
const [role, authenticated] = await Promise.all([
|
|
|
|
this.getRole(roleID, []),
|
|
|
|
strapi.query('plugins::users-permissions.role').findOne({ where: { type: 'authenticated' } }),
|
|
|
|
]);
|
|
|
|
|
|
|
|
await strapi.query('plugins::users-permissions.role').update({
|
|
|
|
where: { id: roleID },
|
|
|
|
data: _.pick(body, ['name', 'description']),
|
|
|
|
});
|
|
|
|
|
|
|
|
await Promise.all(
|
|
|
|
Object.keys(body.permissions || {}).reduce((acc, type) => {
|
|
|
|
Object.keys(body.permissions[type].controllers).forEach(controller => {
|
|
|
|
Object.keys(body.permissions[type].controllers[controller]).forEach(action => {
|
|
|
|
const bodyAction = body.permissions[type].controllers[controller][action];
|
|
|
|
const currentAction = _.get(
|
|
|
|
role.permissions,
|
|
|
|
`${type}.controllers.${controller}.${action}`,
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!_.isEqual(bodyAction, currentAction)) {
|
|
|
|
acc.push(
|
|
|
|
strapi.query('plugins::users-permissions.permission').update({
|
|
|
|
where: {
|
|
|
|
role: roleID,
|
|
|
|
type,
|
|
|
|
controller,
|
|
|
|
action: action.toLowerCase(),
|
|
|
|
},
|
|
|
|
data: bodyAction,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, [])
|
|
|
|
);
|
|
|
|
|
|
|
|
// Add user to this role.
|
|
|
|
const newUsers = _.differenceBy(body.users, role.users, 'id');
|
|
|
|
await Promise.all(newUsers.map(user => this.updateUserRole(user, roleID)));
|
|
|
|
|
|
|
|
const oldUsers = _.differenceBy(role.users, body.users, 'id');
|
|
|
|
await Promise.all(oldUsers.map(user => this.updateUserRole(user, authenticated.id)));
|
|
|
|
},
|
|
|
|
|
|
|
|
async updateUserRole(user, role) {
|
|
|
|
return strapi
|
|
|
|
.query('plugins::users-permissions.user')
|
|
|
|
.update({ where: { id: user.id }, data: { role } });
|
|
|
|
},
|
|
|
|
|
|
|
|
template(layout, data) {
|
|
|
|
const compiledObject = _.template(layout);
|
|
|
|
return compiledObject(data);
|
|
|
|
},
|
|
|
|
};
|