2019-05-29 17:25:56 +02:00

1344 lines
36 KiB
JavaScript

'use strict';
const fs = require('fs');
const path = require('path');
const _ = require('lodash');
const shell = require('shelljs');
module.exports = {
menu: {
sections: [
{
name: 'menu.section.global-settings',
items: [
{
slug: 'application',
name: 'menu.item.application',
icon: 'globe',
},
{
slug: 'languages',
name: 'menu.item.languages',
icon: 'language',
},
],
},
{
name: 'menu.section.environments',
items: [
{
slug: 'databases',
name: 'menu.item.database',
icon: 'database',
},
{
slug: 'request',
name: 'menu.item.request',
icon: 'compress',
},
{
slug: 'response',
name: 'menu.item.response',
icon: 'upload',
},
{
slug: 'security',
name: 'menu.item.security',
icon: 'shield',
},
{
slug: 'server',
name: 'menu.item.server',
icon: 'server',
},
],
},
],
},
application: async () => {
const application = await strapi
.store({
environment: '',
type: 'core',
key: 'application',
})
.get();
return {
name: 'form.application.name',
description: 'form.application.description',
sections: [
{
name: '',
items: [
{
name: 'form.application.item.name',
target: 'application.name',
source: 'db',
type: 'string',
value: _.get(application, 'name', null),
validations: {
maxLength: 255,
required: true,
},
},
{
name: 'form.application.item.description',
target: 'application.description',
source: 'db',
type: 'string',
value: _.get(application, 'description', null),
validations: {
maxLength: 255,
required: true,
},
},
{
name: 'form.application.item.version',
target: 'package.version',
type: 'string',
value: _.get(strapi.config, 'info.version', null),
validations: {
regex: '^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$',
required: true,
},
},
],
},
],
};
},
request: env => ({
name: 'form.request.name',
description: 'form.request.description',
sections: [
{
name: 'form.request.item.logger',
items: [
{
name: 'form.request.item.logger.level',
target: 'request.logger.level',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.request.logger.level`,
null
),
validations: {
required: true,
},
},
{
name: 'form.request.item.logger.exposeInContext',
target: 'request.logger.exposeInContext',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.request.logger.exposeInContext`,
null
),
validations: {
required: true,
},
},
{
name: 'form.request.item.logger.requests',
target: 'request.logger.requests',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.request.logger.requests`,
null
),
validations: {
required: true,
},
},
],
},
{
name: 'form.request.item.parser',
items: [
{
name: 'form.request.item.parser.enabled',
target: 'request.parser.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.request.parser.enabled`,
null
),
items: [
{
name: 'form.request.item.parser.multipart',
target: 'request.parser.multipart',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.request.parser.multipart`,
null
),
validations: {
required: true,
},
},
],
},
],
},
{
name: 'form.request.item.router',
items: [
{
name: 'form.request.item.router.prefix',
target: 'request.router.prefix',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.request.router.prefix`,
null
),
validations: {
required: true,
},
},
],
},
],
}),
response: env => ({
name: 'form.response.name',
description: 'form.response.description',
sections: [
{
name: '',
items: [
{
name: 'form.response.item.gzip.enabled',
target: 'response.gzip.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.response.gzip.enabled`,
null
),
validations: {
required: true,
},
},
],
},
{
name: '',
items: [
{
name: 'form.response.item.responseTime.enabled',
target: 'response.responseTime.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.response.responseTime.enabled`,
null
),
validations: {
required: true,
},
},
],
},
{
name: '',
items: [
{
name: 'form.response.item.poweredBy.enabled',
target: 'response.poweredBy.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.response.poweredBy.enabled`,
null
),
items: [
{
name: 'form.response.item.poweredBy.value',
target: 'response.poweredBy.value',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.response.poweredBy.value`,
null
),
validations: {
required: true,
},
},
],
},
],
},
],
}),
security: env => ({
name: 'form.security.name',
description: 'form.security.description',
sections: [
{
name: 'form.security.item.csrf',
items: [
{
name: 'form.security.item.csrf.enabled',
target: 'security.csrf.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.csrf.enabled`,
null
),
items: [
{
name: 'form.security.item.csrf.key',
target: 'security.csrf.key',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.security.csrf.key`,
null
),
validations: {},
},
{
name: 'form.security.item.csrf.secret',
target: 'security.csrf.secret',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.security.csrf.secret`,
null
),
validations: {},
},
{
name: 'form.security.item.csrf.cookie',
target: 'security.csrf.cookie',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.security.csrf.cookie`,
null
),
validations: {},
},
{
name: 'form.security.item.csrf.angular',
target: 'security.csrf.angular',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.csrf.angular`,
null
),
validations: {},
},
],
validations: {
required: true,
},
},
],
},
{
name: 'form.security.item.p3p',
items: [
{
name: 'form.security.item.p3p.enabled',
target: 'security.p3p.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.p3p.enabled`,
null
),
items: [
{
name: 'form.security.item.p3p.value',
target: 'security.p3p.value',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.security.p3p.value`,
null
),
validations: {
required: true,
},
},
],
validations: {
required: true,
},
},
],
},
{
name: 'form.security.item.hsts',
items: [
{
name: 'form.security.item.hsts.enabled',
target: 'security.hsts.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.hsts.enabled`,
null
),
items: [
{
name: 'form.security.item.hsts.maxAge',
target: 'security.hsts.maxAge',
type: 'number',
value: _.get(
strapi.config,
`environments.${env}.security.hsts.maxAge`,
null
),
validations: {
required: true,
},
},
{
name: 'form.security.item.hsts.includeSubDomains',
target: 'security.hsts.includeSubDomains',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.hsts.includeSubDomains`,
null
),
validations: {},
},
{
name: 'form.security.item.hsts.preload',
target: 'security.hsts.preload',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.hsts.preload`,
null
),
validations: {},
},
],
validations: {
required: true,
},
},
],
},
{
name: 'form.security.item.xframe',
items: [
{
name: 'form.security.item.xframe.enabled',
target: 'security.xframe.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.xframe.enabled`,
null
),
items: [
{
name: 'form.security.item.xframe.value',
target: 'security.xframe.value',
type: 'enum',
value: _.get(
strapi.config,
`environments.${env}.security.xframe.value`,
null
),
items: [
{
name: 'form.security.item.xframe.deny',
value: 'DENY',
},
{
name: 'form.security.item.xframe.sameorigin',
value: 'SAMEORIGIN',
},
{
name: 'form.security.item.xframe.allow-from',
value: 'ALLOW-FROM',
items: [
{
name: '',
target: 'security.xframe.value.nested',
type: 'string',
value: '',
validations: {
required: true,
},
},
],
},
],
validations: {
required: true,
},
},
],
validations: {
required: true,
},
},
],
},
{
name: 'form.security.item.xssProtection',
items: [
{
name: 'form.security.item.xssProtection.enabled',
target: 'security.xssProtection.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.xssProtection.enabled`,
null
),
items: [
{
name: 'form.security.item.xssProtection.mode',
target: 'security.xssProtection.mode',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.security.xssProtection.mode`,
null
),
validations: {},
},
],
validations: {
required: true,
},
},
],
},
{
name: 'form.security.item.cors',
items: [
{
name: 'form.security.item.cors.enabled',
target: 'security.cors.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.security.cors.enabled`,
null
),
items: [
{
name: 'form.security.item.cors.origin',
target: 'security.cors.origin',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.security.cors.origin`,
null
),
validations: {
required: true,
},
},
],
validations: {
required: true,
},
},
],
},
],
}),
server: env => ({
name: 'form.server.name',
description: 'form.server.description',
sections: [
{
name: '',
items: [
{
name: 'form.server.item.host',
target: 'server.host',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.server.host`,
null
),
validations: {},
},
{
name: 'form.server.item.port',
target: 'server.port',
type: 'number',
value: _.get(
strapi.config,
`environments.${env}.server.port`,
null
),
validations: {},
},
{
name: 'form.server.item.cron',
target: 'server.cron.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.server.cron.enabled`,
null
),
},
],
},
{
name: 'form.server.item.proxy',
items: [
{
name: 'form.server.item.proxy.enable',
target: 'server.proxy.enabled',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.server.proxy.enabled`,
null
),
items: [
{
name: 'form.server.item.proxy.host',
target: 'server.proxy.host',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.server.proxy.host`,
null
),
validations: {},
},
{
name: 'form.server.item.proxy.port',
target: 'server.proxy.port',
type: 'number',
value: _.get(
strapi.config,
`environments.${env}.server.proxy.port`,
null
),
validations: {},
},
{
name: 'form.server.item.proxy.ssl',
target: 'server.proxy.ssl',
type: 'boolean',
value: _.get(
strapi.config,
`environments.${env}.server.proxy.ssl`,
null
),
validations: {},
},
],
validations: {},
},
],
},
],
}),
i18n: () => ({
name: 'form.language.name',
description: 'form.language.description',
sections: [
{
name: '',
items: [
{
name: 'form.language.choose',
target: 'language.defaultLocale',
type: 'select',
items: strapi.plugins['settings-manager'].services.languages,
},
],
},
],
}),
databases: (name, env) => ({
name: 'form.database.name',
description: 'form.database.description',
sections: [
{
name: '',
items: [
{
name: 'form.database.item.name',
target: `database.connections.${name}.name`,
type: 'string',
value: name,
validations: {
required: true,
},
},
{
name: 'form.database.item.connector',
target: `database.connections.${name}.connector`,
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.connector`,
null
),
validations: {
required: true,
},
},
{
name: 'form.database.item.client',
target: `database.connections.${name}.settings.client`,
type: 'select',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.settings.client`,
null
),
items: [
{
name: 'form.database.item.provider.mongo',
value: 'mongo',
port: 27017,
},
{
name: 'form.database.item.provider.postgres',
value: 'postgres',
port: 5432,
},
{
name: 'form.database.item.provider.mysql',
value: 'mysql',
port: 3306,
},
{
name: 'form.database.item.provider.redis',
value: 'redis',
port: 6379,
},
],
validations: {
required: true,
},
},
{
name: 'form.database.item.host',
target: `database.connections.${name}.settings.host`,
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.settings.host`,
null
),
validations: {
required: true,
},
},
{
name: 'form.database.item.port',
target: `database.connections.${name}.settings.port`,
type: 'number',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.settings.port`,
null
),
validations: {
required: true,
},
},
{
name: 'form.database.item.database',
target: `database.connections.${name}.settings.database`,
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.settings.database`,
null
),
validations: {
required: true,
},
},
{
name: 'form.database.item.username',
target: `database.connections.${name}.settings.username`,
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.settings.username`,
null
),
validations: {},
},
{
name: 'form.database.item.password',
target: `database.connections.${name}.settings.password`,
type: 'password',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.settings.password`,
null
),
validations: {},
},
{
name: 'form.database.item.authenticationDatabase',
target: `database.connections.${name}.options.authenticationDatabase`,
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.database.connections.${name}.options.authenticationDatabase`,
null
),
validations: {},
},
{
name: 'form.database.item.ssl',
target: `database.connections.${name}.options.ssl`,
type: 'boolean',
value: [true, 'true'].includes(
_.get(
strapi.config,
`environments.${env}.database.connections.${name}.options.ssl`,
false
)
),
validations: {},
},
],
},
{
name: '',
items: [
{
name: 'form.database.item.default',
target: 'database.defaultConnection',
type: 'string',
value: _.get(
strapi.config,
`environments.${env}.database.defaultConnection`,
null
),
validations: {
required: true,
},
},
],
},
],
}),
getEnvironments: () => {
return _.map(_.keys(strapi.config.environments), environment => {
return {
name: environment,
active: strapi.config.environment === environment,
};
});
},
getLanguages: () => {
return _.map(strapi.config.language.locales, language => {
return {
name: language,
active: strapi.config.language.defaultLocale === language,
};
});
},
getDatabases: env => {
const databases = [];
const databasesUsed = [];
_.forEach(strapi.models, model => {
databasesUsed.push(model.connection);
});
_.forEach(
strapi.config.environments[env].database.connections,
(connection, name) =>
databases.push({
connector: _.get(connection, 'connector'),
letter: strapi.plugins[
'settings-manager'
].services.settingsmanager.getClientLetter(
_.get(connection, 'settings.client')
),
color: strapi.plugins[
'settings-manager'
].services.settingsmanager.getClientColor(
_.get(connection, 'settings.client')
),
name,
host: _.get(connection, 'settings.host'),
database: _.get(connection, 'settings.database'),
active:
_.get(
strapi.config,
`environments.${env}.database.defaultConnection`
) === name,
isUsed: _.includes(databasesUsed, name),
})
);
return databases;
},
getClientConnector: client => {
const bookshelfClients = ['postgres', 'mysql'];
const mongooseClients = ['mongo'];
const redisClients = ['redis'];
let connector;
if (_.indexOf(bookshelfClients, client) !== -1)
connector = 'strapi-hook-bookshelf';
if (_.indexOf(mongooseClients, client) !== -1)
connector = 'strapi-hook-mongoose';
if (_.indexOf(redisClients, client) !== -1) connector = 'strapi-hook-redis';
return connector;
},
getClientColor: client => {
switch (client) {
case 'postgres':
return '#ffb500';
case 'mysql':
return '#4479a1';
case 'redis':
return '#ff5d00';
case 'mongo':
return '#43b121';
default:
return '#000000';
}
},
getClientLetter: client => {
switch (client) {
case 'postgres':
return 'PG';
case 'mysql':
return 'MY';
default:
return _.upperCase(_.head(client));
}
},
getItems: model => {
return _.flatten(
_.map(model.sections, section => {
let items = section.items;
_.forEach(items, item => {
if (item.type === 'boolean' && _.has(item, 'items'))
items = _.concat(items, item.items);
});
return items;
})
);
},
cleanParams: (params, items) => {
const cleanParams = {};
_.forEach(items, ({ target }) =>
_.has(params, target)
? _.set(cleanParams, target, _.get(params, target))
: ''
);
return cleanParams;
},
formatErrors: errors =>
_.map(_.groupBy(errors, 'target'), (errs, target) => {
return {
target,
messages: _.map(errs, err => {
return {
id: err.message,
params: _.get(err, 'params', undefined),
};
}),
};
}),
paramsValidation: (params, items) => {
let errors = [];
const reformat = (value, format) => {
if (format === 'number')
try {
return parseFloat(value);
} catch (e) {
return null;
}
if (format === 'boolean') return value === 'true';
return value;
};
const checkType = (input, { type, target, items }) => {
if (
(type === 'string' || type === 'text' || type === 'password') &&
!_.isString(input)
)
return errors.push({
target: target,
message: 'request.error.type.string',
});
if (type === 'number' && !_.isNumber(input))
return errors.push({
target: target,
message: 'request.error.type.number',
});
if (type === 'boolean' && !_.isBoolean(input))
return errors.push({
target: target,
message: 'request.error.type.boolean',
});
if (type === 'select' && !_.find(items, { value: input }))
return errors.push({
target: target,
message: 'request.error.type.select',
});
if (type === 'enum' && !_.find(items, { value: input })) {
const key = input.split('.')[0];
input = _.drop(input.split('.')).join('.');
const item = _.find(items, { value: key });
if (!item)
return errors.push({
target: target,
message: 'request.error.type.enum',
});
input = reformat(input, item.type);
params[target] = input;
_.forEach(item.items, subItem => {
subItem.target = target;
if (_.has(params, subItem.target)) {
const input = _.get(params, subItem.target, null);
checkType(input, subItem);
checkValidations(input, subItem);
}
});
}
};
const checkValidations = (input, item) => {
_.forEach(item.validations, (value, key) => {
if (
key === 'required' &&
(_.isNull(input) ||
(_.isString(input) && _.isEmpty(input)) ||
_.isUndefined(input))
)
errors.push({
target: item.target,
message: 'request.error.validation.required',
});
if (key === 'regex' && !new RegExp(value).test(input))
errors.push({
target: item.target,
message: 'request.error.validation.regex',
});
if (key === 'max' && parseInt(input) > value)
errors.push({
target: item.target,
message: 'request.error.validation.max',
});
if (key === 'min' && parseInt(input) < value)
errors.push({
target: item.target,
message: 'request.error.validation.min',
});
if (key === 'maxLength' && input.length > value)
errors.push({
target: item.target,
message: 'request.error.validation.maxLength',
});
if (key === 'minLength' && input.length < value)
errors.push({
target: item.target,
message: 'request.error.validation.minLength',
});
});
};
_.forEach(items, item => {
if (_.has(params, item.target)) {
const input = _.get(params, item.target, null);
checkType(input, item);
checkValidations(input, item);
}
});
return [params, errors];
},
updateSettings: async (params, items, env = '') => {
const appPath = strapi.config.appPath;
const errors = [];
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}
await asyncForEach(items, async ({ target, source }) => {
if (_.has(params, target)) {
let input = _.get(params, target, null);
const [file, ...objPath] = target.split('.');
if (source === 'db') {
const store = strapi.store({
environment: env,
type: 'core',
key: file,
});
const data = await store.get();
_.set(data, objPath, input);
await store.set({ value: data });
return;
}
if (target === 'language.defaultLocale')
input = _.lowerCase(input).replace(/ /g, '_');
const filePath =
file === 'package'
? path.join(appPath, 'package.json')
: path.join(
appPath,
'config',
`${env ? `environments/${env}` : ''}`,
`${_.replace(file, '.', '/')}.json`
);
try {
const fileContent = require(filePath);
_.set(fileContent, objPath, input);
try {
fs.writeFileSync(
filePath,
JSON.stringify(fileContent, null, 2),
'utf8'
);
} catch (e) {
errors.push({
target,
message: 'request.error.config',
params: {
filePath: filePath,
},
});
}
} catch (e) {
errors.push({
target,
message: 'request.error.config',
params: {
filePath: filePath,
},
});
}
}
});
return errors;
},
installDependency: (params, name) => {
const clientsDependencies = {
postgres: 'pg',
mysql: 'mysql',
};
const client = _.get(
clientsDependencies,
_.get(params, `database.connections.${name}.settings.client`)
);
const installedClient =
_.indexOf(_.keys(strapi.config.info.dependencies), client) !== -1;
const connector = _.get(params, `database.connections.${name}.connector`);
const installedConnector =
_.indexOf(_.keys(strapi.config.info.dependencies), connector) !== -1;
if (connector && !installedConnector) {
strapi.log.info(`Installing ${connector} dependency ...`);
shell.exec(`npm install ${connector}@${strapi.config.info.strapi}`, {
silent: true,
});
}
if (client && !installedClient) {
strapi.log.info(`Installing ${client} dependency ...`);
shell.exec(`npm install ${client}`, { silent: true });
}
},
cleanDependency: (env, config) => {
const availableConnectors = [
'strapi-hook-mongoose',
'strapi-hook-bookshelf',
'strapi-hook-redis',
];
let usedConnectors = [];
const errors = [];
_.forEach(_.keys(strapi.config.environments), environment => {
let connections =
strapi.config.environments[environment].database.connections;
if (environment === env) {
connections = config.database.connections;
}
_.forEach(connections, connection => {
if (_.get(connection, 'connector')) {
usedConnectors.push(connection.connector);
}
});
});
usedConnectors = _.uniq(usedConnectors);
_.forEach(availableConnectors, connector => {
const installed =
_.indexOf(_.keys(strapi.config.info.dependencies), connector) !== -1;
const used = _.indexOf(usedConnectors, connector) !== -1;
if (installed && !used) {
const filePath = path.join(strapi.config.appPath, 'package.json');
try {
const fileContent = require(filePath);
_.set(fileContent, `dependencies.${connector}`, undefined);
try {
fs.writeFileSync(
filePath,
JSON.stringify(fileContent, null, 2),
'utf8'
);
} catch (e) {
errors.push({
target: connector,
message: 'request.error.config',
params: {
filePath: filePath,
},
});
}
} catch (e) {
errors.push({
target: connector,
message: 'request.error.config',
params: {
filePath: filePath,
},
});
}
}
});
return errors;
},
getModelPath: model => {
let searchFilePath;
const errors = [];
const searchFileName = `${model}.settings.json`;
const apiPath = path.join(strapi.config.appPath, 'api');
let apis;
try {
apis = fs.readdirSync(apiPath);
_.forEach(apis, api => {
const modelsPath = path.join(apiPath, api, 'models');
let models;
try {
models = fs.readdirSync(modelsPath);
const modelIndex = _.indexOf(
_.map(models, model => _.toLower(model)),
searchFileName
);
if (modelIndex !== -1)
searchFilePath = `${modelsPath}/${models[modelIndex]}`;
} catch (e) {
errors.push({
id: 'request.error.folder.read',
params: {
folderPath: modelsPath,
},
});
}
});
} catch (e) {
errors.push({
id: 'request.error.folder.read',
params: {
folderPath: apiPath,
},
});
}
return [searchFilePath, errors];
},
};