| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- const loggerFactory = require('@alias/logger');
- const logger = loggerFactory('growi:routes:apiv3:app-settings');
- const debug = require('debug')('growi:routes:admin');
- const express = require('express');
- const { listLocaleIds } = require('@commons/util/locale-utils');
- const router = express.Router();
- const { body } = require('express-validator');
- const ErrorV3 = require('../../models/vo/error-apiv3');
- /**
- * @swagger
- * tags:
- * name: AppSettings
- */
- /**
- * @swagger
- *
- * components:
- * schemas:
- * AppSettingParams:
- * description: AppSettingParams
- * type: object
- * properties:
- * title:
- * type: string
- * description: site name show on page header and tilte of HTML
- * confidential:
- * type: string
- * description: confidential show on page header
- * globalLang:
- * type: string
- * description: language set when create user
- * fileUpload:
- * type: boolean
- * description: enable upload file except image file
- * SiteUrlSettingParams:
- * description: SiteUrlSettingParams
- * type: object
- * properties:
- * siteUrl:
- * type: string
- * description: Site URL. e.g. https://example.com, https://example.com:8080
- * envSiteUrl:
- * type: string
- * description: environment variable 'APP_SITE_URL'
- * MailSetting:
- * description: MailSettingParams
- * type: object
- * properties:
- * fromAddress:
- * type: string
- * description: e-mail address used as from address of mail which sent from GROWI app
- * transmissionMethod:
- * type: string
- * description: transmission method
- * SmtpSettingParams:
- * description: SmtpSettingParams
- * type: object
- * properties:
- * smtpHost:
- * type: string
- * description: host name of client's smtp server
- * smtpPort:
- * type: string
- * description: port of client's smtp server
- * smtpUser:
- * type: string
- * description: user name of client's smtp server
- * smtpPassword:
- * type: string
- * description: password of client's smtp server
- * SesSettingParams:
- * description: SesSettingParams
- * type: object
- * properties:
- * accessKeyId:
- * type: string
- * description: accesskey id for authentification of AWS
- * secretAccessKey:
- * type: string
- * description: secret key for authentification of AWS
- * AwsSettingParams:
- * description: AwsSettingParams
- * type: object
- * properties:
- * region:
- * type: string
- * description: region of AWS S3
- * customEndpoint:
- * type: string
- * description: custom endpoint of AWS S3
- * bucket:
- * type: string
- * description: AWS S3 bucket name
- * accessKeyId:
- * type: string
- * description: accesskey id for authentification of AWS
- * secretAccessKey:
- * type: string
- * description: secret key for authentification of AWS
- * GcpSettingParams:
- * description: GcpSettingParams
- * type: object
- * properties:
- * gcsApiKeyJsonPath:
- * type: string
- * description: apiKeyJsonPath of gcp
- * gcsBucket:
- * type: string
- * description: bucket name of gcs
- * gcsUploadNamespace:
- * type: string
- * description: name space of gcs
- * envGcsApiKeyJsonPath:
- * type: string
- * description: Path of the JSON file that contains service account key to authenticate to GCP API
- * envGcsBucket:
- * type: string
- * description: Name of the GCS bucket
- * envGcsUploadNamespace:
- * type: string
- * description: Directory name to create in the bucket
- * PluginSettingParams:
- * description: PluginSettingParams
- * type: object
- * properties:
- * isEnabledPlugins:
- * type: string
- * description: enable use plugins
- */
- module.exports = (crowi) => {
- const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
- const loginRequired = require('../../middlewares/login-required')(crowi);
- const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
- const adminRequired = require('../../middlewares/admin-required')(crowi);
- const csrf = require('../../middlewares/csrf')(crowi);
- const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
- const validator = {
- appSetting: [
- body('title').trim(),
- body('confidential'),
- body('globalLang').isIn(listLocaleIds()),
- body('fileUpload').isBoolean(),
- ],
- siteUrlSetting: [
- body('siteUrl').trim().matches(/^(https?:\/\/[^/]+|)$/).isURL({ require_tld: false }),
- ],
- mailSetting: [
- body('fromAddress').trim().if(value => value !== '').isEmail(),
- body('transmissionMethod').isIn(['smtp', 'ses']),
- ],
- smtpSetting: [
- body('smtpHost').trim(),
- body('smtpPort').trim().if(value => value !== '').isPort(),
- body('smtpUser').trim(),
- body('smtpPassword').trim(),
- ],
- sesSetting: [
- body('sesAccessKeyId').trim().if(value => value !== '').matches(/^[\da-zA-Z]+$/),
- body('sesSecretAccessKey').trim(),
- ],
- awsSetting: [
- body('region').trim().matches(/^[a-z]+-[a-z]+-\d+$/).withMessage((value, { req }) => req.t('validation.aws_region')),
- body('customEndpoint').trim().matches(/^(https?:\/\/[^/]+|)$/).withMessage((value, { req }) => req.t('validation.aws_custom_endpoint')),
- body('bucket').trim(),
- body('accessKeyId').trim().if(value => value !== '').matches(/^[\da-zA-Z]+$/),
- body('secretAccessKey').trim(),
- ],
- gcpSetting: [
- body('gcsApiKeyJsonPath').trim(),
- body('gcsBucket').trim(),
- body('gcsUploadNamespace').trim(),
- ],
- pluginSetting: [
- body('isEnabledPlugins').isBoolean(),
- ],
- };
- /**
- * @swagger
- *
- * /app-settings:
- * get:
- * tags: [AppSettings]
- * operationId: getAppSettings
- * summary: /app-settings
- * description: get app setting params
- * responses:
- * 200:
- * description: Resources are available
- * content:
- * application/json:
- * schema:
- * properties:
- * appSettingsParams:
- * type: object
- * description: app settings params
- */
- router.get('/', accessTokenParser, loginRequired, adminRequired, async(req, res) => {
- const appSettingsParams = {
- title: crowi.configManager.getConfig('crowi', 'app:title'),
- confidential: crowi.configManager.getConfig('crowi', 'app:confidential'),
- globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
- fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
- siteUrl: crowi.configManager.getConfig('crowi', 'app:siteUrl'),
- envSiteUrl: crowi.configManager.getConfigFromEnvVars('crowi', 'app:siteUrl'),
- isMailerSetup: crowi.mailService.isMailerSetup,
- fromAddress: crowi.configManager.getConfig('crowi', 'mail:from'),
- transmissionMethod: crowi.configManager.getConfig('crowi', 'mail:transmissionMethod'),
- smtpHost: crowi.configManager.getConfig('crowi', 'mail:smtpHost'),
- smtpPort: crowi.configManager.getConfig('crowi', 'mail:smtpPort'),
- smtpUser: crowi.configManager.getConfig('crowi', 'mail:smtpUser'),
- smtpPassword: crowi.configManager.getConfig('crowi', 'mail:smtpPassword'),
- sesAccessKeyId: crowi.configManager.getConfig('crowi', 'mail:sesAccessKeyId'),
- sesSecretAccessKey: crowi.configManager.getConfig('crowi', 'mail:sesSecretAccessKey'),
- region: crowi.configManager.getConfig('crowi', 'aws:region'),
- customEndpoint: crowi.configManager.getConfig('crowi', 'aws:customEndpoint'),
- bucket: crowi.configManager.getConfig('crowi', 'aws:bucket'),
- accessKeyId: crowi.configManager.getConfig('crowi', 'aws:accessKeyId'),
- secretAccessKey: crowi.configManager.getConfig('crowi', 'aws:secretAccessKey'),
- envGcsApiKeyJsonPath: crowi.configManager.getConfigFromEnvVars('crowi', 'gcs:apiKeyJsonPath'),
- envGcsBucket: crowi.configManager.getConfigFromEnvVars('crowi', 'gcs:bucket'),
- envGcsUploadNamespace: crowi.configManager.getConfigFromEnvVars('crowi', 'gcs:uploadNamespace'),
- isEnabledPlugins: crowi.configManager.getConfig('crowi', 'plugin:isEnabledPlugins'),
- };
- return res.apiv3({ appSettingsParams });
- });
- /**
- * @swagger
- *
- * /app-settings/app-setting:
- * put:
- * tags: [AppSettings]
- * summary: /app-settings/app-setting
- * operationId: updateAppSettings
- * description: Update app setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/AppSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update app setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/AppSettingParams'
- */
- router.put('/app-setting', loginRequiredStrictly, adminRequired, csrf, validator.appSetting, apiV3FormValidator, async(req, res) => {
- const requestAppSettingParams = {
- 'app:title': req.body.title,
- 'app:confidential': req.body.confidential,
- 'app:globalLang': req.body.globalLang,
- 'app:fileUpload': req.body.fileUpload,
- };
- try {
- await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestAppSettingParams);
- const appSettingParams = {
- title: crowi.configManager.getConfig('crowi', 'app:title'),
- confidential: crowi.configManager.getConfig('crowi', 'app:confidential'),
- globalLang: crowi.configManager.getConfig('crowi', 'app:globalLang'),
- fileUpload: crowi.configManager.getConfig('crowi', 'app:fileUpload'),
- };
- return res.apiv3({ appSettingParams });
- }
- catch (err) {
- const msg = 'Error occurred in updating app setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-appSetting-failed'));
- }
- });
- /**
- * @swagger
- *
- * /app-settings/site-url-setting:
- * put:
- * tags: [AppSettings]
- * operationId: updateAppSettingSiteUrlSetting
- * summary: /app-settings/site-url-setting
- * description: Update site url setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SiteUrlSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update site url setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SiteUrlSettingParams'
- */
- router.put('/site-url-setting', loginRequiredStrictly, adminRequired, csrf, validator.siteUrlSetting, apiV3FormValidator, async(req, res) => {
- const requestSiteUrlSettingParams = {
- 'app:siteUrl': req.body.siteUrl,
- };
- try {
- await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestSiteUrlSettingParams);
- const siteUrlSettingParams = {
- siteUrl: crowi.configManager.getConfig('crowi', 'app:siteUrl'),
- };
- return res.apiv3({ siteUrlSettingParams });
- }
- catch (err) {
- const msg = 'Error occurred in updating site url setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-siteUrlSetting-failed'));
- }
- });
- /**
- * send mail (Promise wrapper)
- */
- async function sendMailPromiseWrapper(smtpClient, options) {
- return new Promise((resolve, reject) => {
- smtpClient.sendMail(options, (err, res) => {
- if (err) {
- reject(err);
- }
- else {
- resolve(res);
- }
- });
- });
- }
- /**
- * validate mail setting send test mail
- */
- async function sendTestEmail(destinationAddress) {
- const { configManager, mailService } = crowi;
- if (!mailService.isMailerSetup) {
- throw Error('mailService is not setup');
- }
- const fromAddress = configManager.getConfig('crowi', 'mail:from');
- if (fromAddress == null) {
- throw Error('fromAddress is not setup');
- }
- const smtpHost = configManager.getConfig('crowi', 'mail:smtpHost');
- const smtpPort = configManager.getConfig('crowi', 'mail:smtpPort');
- const smtpUser = configManager.getConfig('crowi', 'mail:smtpUser');
- const smtpPassword = configManager.getConfig('crowi', 'mail:smtpPassword');
- const option = {
- host: smtpHost,
- port: smtpPort,
- };
- if (smtpUser && smtpPassword) {
- option.auth = {
- user: smtpUser,
- pass: smtpPassword,
- };
- }
- if (option.port === 465) {
- option.secure = true;
- }
- const smtpClient = mailService.createSMTPClient(option);
- debug('mailer setup for validate SMTP setting', smtpClient);
- const mailOptions = {
- from: fromAddress,
- to: destinationAddress,
- subject: 'Wiki管理設定のアップデートによるメール通知',
- text: 'このメールは、WikiのSMTP設定のアップデートにより送信されています。',
- };
- await sendMailPromiseWrapper(smtpClient, mailOptions);
- }
- const updateMailSettinConfig = async function(requestMailSettingParams) {
- const {
- configManager,
- mailService,
- } = crowi;
- // update config without publishing S2sMessage
- await configManager.updateConfigsInTheSameNamespace('crowi', requestMailSettingParams, true);
- await mailService.initialize();
- mailService.publishUpdatedMessage();
- return {
- isMailerSetup: mailService.isMailerSetup,
- fromAddress: configManager.getConfig('crowi', 'mail:from'),
- smtpHost: configManager.getConfig('crowi', 'mail:smtpHost'),
- smtpPort: configManager.getConfig('crowi', 'mail:smtpPort'),
- smtpUser: configManager.getConfig('crowi', 'mail:smtpUser'),
- smtpPassword: configManager.getConfig('crowi', 'mail:smtpPassword'),
- sesAccessKeyId: configManager.getConfig('crowi', 'mail:sesAccessKeyId'),
- sesSecretAccessKey: configManager.getConfig('crowi', 'mail:sesSecretAccessKey'),
- };
- };
- /**
- * @swagger
- *
- * /app-settings/smtp-setting:
- * put:
- * tags: [AppSettings]
- * operationId: updateAppSettingSmtpSetting
- * summary: /app-settings/smtp-setting
- * description: Update smtp setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SmtpSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update smtp setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SmtpSettingParams'
- */
- router.put('/smtp-setting', loginRequiredStrictly, adminRequired, csrf, validator.smtpSetting, apiV3FormValidator, async(req, res) => {
- const requestMailSettingParams = {
- 'mail:from': req.body.fromAddress,
- 'mail:transmissionMethod': req.body.transmissionMethod,
- 'mail:smtpHost': req.body.smtpHost,
- 'mail:smtpPort': req.body.smtpPort,
- 'mail:smtpUser': req.body.smtpUser,
- 'mail:smtpPassword': req.body.smtpPassword,
- };
- try {
- const mailSettingParams = await updateMailSettinConfig(requestMailSettingParams);
- return res.apiv3({ mailSettingParams });
- }
- catch (err) {
- const msg = 'Error occurred in updating smtp setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-smtpSetting-failed'));
- }
- });
- /**
- * @swagger
- *
- * /app-settings/smtp-test:
- * post:
- * tags: [AppSettings]
- * operationId: postSmtpTest
- * summary: /app-settings/smtp-setting
- * description: Send test mail for smtp
- * responses:
- * 200:
- * description: Succeeded to send test mail for smtp
- */
- router.post('/smtp-test', loginRequiredStrictly, adminRequired, async(req, res) => {
- try {
- await sendTestEmail(req.user.email);
- return res.apiv3({});
- }
- catch (err) {
- const msg = req.t('validation.failed_to_send_a_test_email');
- logger.error('Error', err);
- debug('Error validate mail setting: ', err);
- return res.apiv3Err(new ErrorV3(msg, 'send-email-with-smtp-failed'));
- }
- });
- /**
- * @swagger
- *
- * /app-settings/ses-setting:
- * put:
- * tags: [AppSettings]
- * operationId: updateAppSettingSesSetting
- * summary: /app-settings/ses-setting
- * description: Update ses setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SesSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update ses setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/SesSettingParams'
- */
- router.put('/ses-setting', loginRequiredStrictly, adminRequired, csrf, validator.sesSetting, apiV3FormValidator, async(req, res) => {
- const { mailService } = crowi;
- const requestSesSettingParams = {
- 'mail:from': req.body.fromAddress,
- 'mail:transmissionMethod': req.body.transmissionMethod,
- 'mail:sesAccessKeyId': req.body.sesAccessKeyId,
- 'mail:sesSecretAccessKey': req.body.sesSecretAccessKey,
- };
- let mailSettingParams;
- try {
- mailSettingParams = await updateMailSettinConfig(requestSesSettingParams);
- }
- catch (err) {
- const msg = 'Error occurred in updating ses setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-ses-setting-failed'));
- }
- await mailService.initialize();
- mailService.publishUpdatedMessage();
- return res.apiv3({ mailSettingParams });
- });
- /**
- * @swagger
- *
- * /app-settings/aws-setting:
- * put:
- * tags: [AppSettings]
- * operationId: updateAppSettingAwsSetting
- * summary: /app-settings/aws-setting
- * description: Update aws setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/AwsSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update aws setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/AwsSettingParams'
- */
- router.put('/aws-setting', loginRequiredStrictly, adminRequired, csrf, validator.awsSetting, apiV3FormValidator, async(req, res) => {
- const requestAwsSettingParams = {
- 'aws:region': req.body.region,
- 'aws:customEndpoint': req.body.customEndpoint,
- 'aws:bucket': req.body.bucket,
- 'aws:accessKeyId': req.body.accessKeyId,
- 'aws:secretAccessKey': req.body.secretAccessKey,
- };
- try {
- await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestAwsSettingParams);
- // TODO GW-3797 re-setup file uploader
- const awsSettingParams = {
- region: crowi.configManager.getConfig('crowi', 'aws:region'),
- customEndpoint: crowi.configManager.getConfig('crowi', 'aws:customEndpoint'),
- bucket: crowi.configManager.getConfig('crowi', 'aws:bucket'),
- accessKeyId: crowi.configManager.getConfig('crowi', 'aws:accessKeyId'),
- secretAccessKey: crowi.configManager.getConfig('crowi', 'aws:secretAccessKey'),
- };
- return res.apiv3({ awsSettingParams });
- }
- catch (err) {
- const msg = 'Error occurred in updating aws setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-awsSetting-failed'));
- }
- });
- /**
- * @swagger
- *
- * /app-settings/gcp-setting:
- * put:
- * tags: [AppSettings]
- * operationId: updateAppSettingGcpSetting
- * summary: /app-settings/gcp-setting
- * description: Update gcp setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/GcpSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update gcp setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/GcpSettingParams'
- */
- router.put('/gcp-setting', loginRequiredStrictly, adminRequired, csrf, validator.gcpSetting, apiV3FormValidator, async(req, res) => {
- const requestGcpSettingParams = {
- 'gcs:apiKeyJsonPath': req.body.gcsApiKeyJsonPath,
- 'gcs:bucket': req.body.gcsBucket,
- 'gcs:uploadNamespace': req.body.gcsUploadNamespace,
- };
- try {
- await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestGcpSettingParams);
- // TODO GW-3797 re-setup file uploader
- const gcpSettingParams = {
- gcsApiKeyJsonPath: crowi.configManager.getConfig('crowi', 'gcs:apiKeyJsonPath'),
- gcsBucket: crowi.configManager.getConfig('crowi', 'gcs:bucket'),
- gcsUploadNamespace: crowi.configManager.getConfig('crowi', 'gcs:uploadNamespace'),
- };
- return res.apiv3({ gcpSettingParams });
- }
- catch (err) {
- const msg = 'Error occurred in updating aws setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-awsSetting-failed'));
- }
- });
- /**
- * @swagger
- *
- * /app-settings/plugin-setting:
- * put:
- * tags: [AppSettings]
- * operationId: updateAppSettingPluginSetting
- * summary: /app-settings/plugin-setting
- * description: Update plugin setting
- * requestBody:
- * required: true
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/PluginSettingParams'
- * responses:
- * 200:
- * description: Succeeded to update plugin setting
- * content:
- * application/json:
- * schema:
- * $ref: '#/components/schemas/PluginSettingParams'
- */
- router.put('/plugin-setting', loginRequiredStrictly, adminRequired, csrf, validator.pluginSetting, apiV3FormValidator, async(req, res) => {
- const requestPluginSettingParams = {
- 'plugin:isEnabledPlugins': req.body.isEnabledPlugins,
- };
- try {
- await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestPluginSettingParams);
- const pluginSettingParams = {
- isEnabledPlugins: crowi.configManager.getConfig('crowi', 'plugin:isEnabledPlugins'),
- };
- return res.apiv3({ pluginSettingParams });
- }
- catch (err) {
- const msg = 'Error occurred in updating plugin setting';
- logger.error('Error', err);
- return res.apiv3Err(new ErrorV3(msg, 'update-pluginSetting-failed'));
- }
- });
- return router;
- };
|