Просмотр исходного кода

Merge branch 'master' into imprv/separate-ses-settings

itizawa 5 лет назад
Родитель
Сommit
3c1df17f6a

+ 4 - 0
CHANGES.md

@@ -5,6 +5,10 @@
 * Feature: Create/edit linker with GUI
 * Feature: Create/edit linker with GUI
 * Improvement: Paging page histories
 * Improvement: Paging page histories
 * Fix: To be able to delete attachment metadata even when the actual data does not exist
 * Fix: To be able to delete attachment metadata even when the actual data does not exist
+* Fix: Limit the attrubutes of user data for `/_api/v3/users`
+* Upgrade libs
+    * optimize-css-assets-webpack-plugin
+    * terser-webpack-plugin
 
 
 ## v4.1.2
 ## v4.1.2
 
 

+ 1 - 0
config/webpack.prod.js

@@ -67,6 +67,7 @@ module.exports = require('./webpack.common')({
 
 
   ],
   ],
   optimization: {
   optimization: {
+    minimize: true,
     minimizer: [
     minimizer: [
       new TerserPlugin({}),
       new TerserPlugin({}),
       new OptimizeCSSAssetsPlugin({}),
       new OptimizeCSSAssetsPlugin({}),

+ 2 - 2
package.json

@@ -220,7 +220,7 @@
     "normalize-path": "^3.0.0",
     "normalize-path": "^3.0.0",
     "null-loader": "^3.0.0",
     "null-loader": "^3.0.0",
     "on-headers": "^1.0.1",
     "on-headers": "^1.0.1",
-    "optimize-css-assets-webpack-plugin": "^5.0.0",
+    "optimize-css-assets-webpack-plugin": "^5.0.3",
     "penpal": "^4.0.0",
     "penpal": "^4.0.0",
     "plantuml-encoder": "^1.2.5",
     "plantuml-encoder": "^1.2.5",
     "postcss-loader": "^3.0.0",
     "postcss-loader": "^3.0.0",
@@ -249,7 +249,7 @@
     "stylelint-config-recess-order": "^2.0.1",
     "stylelint-config-recess-order": "^2.0.1",
     "swagger-jsdoc": "^3.4.0",
     "swagger-jsdoc": "^3.4.0",
     "swagger2openapi": "^5.3.1",
     "swagger2openapi": "^5.3.1",
-    "terser-webpack-plugin": "^2.0.1",
+    "terser-webpack-plugin": "^4.1.0",
     "throttle-debounce": "^2.0.0",
     "throttle-debounce": "^2.0.0",
     "toastr": "^2.1.2",
     "toastr": "^2.1.2",
     "unstated": "^2.1.1",
     "unstated": "^2.1.1",

+ 80 - 59
src/client/js/components/Admin/App/MailSetting.jsx

@@ -29,6 +29,7 @@ class MailSetting extends React.Component {
 
 
     this.openInitializeValueModal = this.openInitializeValueModal.bind(this);
     this.openInitializeValueModal = this.openInitializeValueModal.bind(this);
     this.closeInitializeValueModal = this.closeInitializeValueModal.bind(this);
     this.closeInitializeValueModal = this.closeInitializeValueModal.bind(this);
+    this.submitFromAdressHandler = this.submitFromAdressHandler.bind(this);
     this.submitHandler = this.submitHandler.bind(this);
     this.submitHandler = this.submitHandler.bind(this);
     this.initialize = this.initialize.bind(this);
     this.initialize = this.initialize.bind(this);
   }
   }
@@ -54,14 +55,26 @@ class MailSetting extends React.Component {
     }
     }
   }
   }
 
 
+  async submitFromAdressHandler() {
+    const { t, adminAppContainer } = this.props;
+
+    try {
+      await adminAppContainer.updateFromAdressHandler();
+      toastSuccess(t('toaster.update_successed', { target: t('admin:app_setting.mail_settings') }));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
   async initialize() {
   async initialize() {
     const { t, adminAppContainer } = this.props;
     const { t, adminAppContainer } = this.props;
 
 
     try {
     try {
       const mailSettingParams = await adminAppContainer.initializeMailSettingHandler();
       const mailSettingParams = await adminAppContainer.initializeMailSettingHandler();
-      toastSuccess(t('toaster.initialize_successed', { target: t('admin:app_setting.mail_settings') }));
+      toastSuccess(t('toaster.initialize_successed', { target: t('admin:app_setting.smtp_settings') }));
       // convert values to '' if value is null for overwriting values of inputs with refs
       // convert values to '' if value is null for overwriting values of inputs with refs
-      this.emailInput.current.value = mailSettingParams.fromAddress || '';
       this.hostInput.current.value = mailSettingParams.smtpHost || '';
       this.hostInput.current.value = mailSettingParams.smtpHost || '';
       this.portInput.current.value = mailSettingParams.smtpPort || '';
       this.portInput.current.value = mailSettingParams.smtpPort || '';
       this.userInput.current.value = mailSettingParams.smtpUser || '';
       this.userInput.current.value = mailSettingParams.smtpUser || '';
@@ -93,70 +106,78 @@ class MailSetting extends React.Component {
             />
             />
           </div>
           </div>
         </div>
         </div>
-
-        <div className="row form-group mb-5">
-          <label className="col-md-3 col-form-label text-left">{t('admin:app_setting.smtp_settings')}</label>
-          <div className="col-md-4">
-            <label>{t('admin:app_setting.host')}</label>
-            <input
-              className="form-control"
-              type="text"
-              ref={this.hostInput}
-              defaultValue={adminAppContainer.state.smtpHost || ''}
-              onChange={(e) => { adminAppContainer.changeSmtpHost(e.target.value) }}
-            />
-          </div>
-          <div className="col-md-2">
-            <label>{t('admin:app_setting.port')}</label>
-            <input
-              className="form-control"
-              ref={this.portInput}
-              defaultValue={adminAppContainer.state.smtpPort || ''}
-              onChange={(e) => { adminAppContainer.changeSmtpPort(e.target.value) }}
-            />
+        <div className="row my-3">
+          <div className="mx-auto">
+            <button type="button" className="btn btn-primary" onClick={this.submitFromAdressHandler}>{ t('Update') }</button>
           </div>
           </div>
         </div>
         </div>
-
-        <div className="row form-group mb-5">
-          <div className="col-md-3 offset-md-3">
-            <label>{t('admin:app_setting.user')}</label>
-            <input
-              className="form-control"
-              type="text"
-              ref={this.userInput}
-              defaultValue={adminAppContainer.state.smtpUser || ''}
-              onChange={(e) => { adminAppContainer.changeSmtpUser(e.target.value) }}
-            />
-          </div>
-          <div className="col-md-3">
-            <label>{t('Password')}</label>
-            <input
-              className="form-control"
-              type="password"
-              ref={this.passwordInput}
-              defaultValue={adminAppContainer.state.smtpPassword || ''}
-              onChange={(e) => { adminAppContainer.changeSmtpPassword(e.target.value) }}
-            />
+        <div id="mail-smtp" className="tab-pane active mt-5">
+          <div className="row form-group mb-5">
+            <label className="col-md-3 col-form-label text-left">{t('admin:app_setting.smtp_settings')}</label>
+            <div className="col-md-4">
+              <label>{t('admin:app_setting.host')}</label>
+              <input
+                className="form-control"
+                type="text"
+                ref={this.hostInput}
+                defaultValue={adminAppContainer.state.smtpHost || ''}
+                onChange={(e) => { adminAppContainer.changeSmtpHost(e.target.value) }}
+              />
+            </div>
+            <div className="col-md-2">
+              <label>{t('admin:app_setting.port')}</label>
+              <input
+                className="form-control"
+                ref={this.portInput}
+                defaultValue={adminAppContainer.state.smtpPort || ''}
+                onChange={(e) => { adminAppContainer.changeSmtpPort(e.target.value) }}
+              />
+            </div>
           </div>
           </div>
-        </div>
 
 
-        <div className="row my-3">
-          <div className="offset-5">
-            <button type="button" className="btn btn-primary" onClick={this.submitHandler} disabled={adminAppContainer.state.retrieveError != null}>
-              { t('Update') }
-            </button>
+          <div className="row form-group mb-5">
+            <div className="col-md-3 offset-md-3">
+              <label>{t('admin:app_setting.user')}</label>
+              <input
+                className="form-control"
+                type="text"
+                ref={this.userInput}
+                defaultValue={adminAppContainer.state.smtpUser || ''}
+                onChange={(e) => { adminAppContainer.changeSmtpUser(e.target.value) }}
+              />
+            </div>
+            <div className="col-md-3">
+              <label>{t('Password')}</label>
+              <input
+                className="form-control"
+                type="password"
+                ref={this.passwordInput}
+                defaultValue={adminAppContainer.state.smtpPassword || ''}
+                onChange={(e) => { adminAppContainer.changeSmtpPassword(e.target.value) }}
+              />
+            </div>
           </div>
           </div>
-          <div className="offset-1">
-            <button
-              type="button"
-              className="btn btn-secondary"
-              onClick={this.openInitializeValueModal}
-              disabled={adminAppContainer.state.retrieveError != null}
-            >
-              {t('admin:app_setting.initialize_mail_settings')}
-            </button>
+
+          <div className="row my-3">
+            <div className="offset-5">
+              <button type="button" className="btn btn-primary" onClick={this.submitHandler} disabled={adminAppContainer.state.retrieveError != null}>
+                { t('Update') }
+              </button>
+            </div>
+            <div className="offset-1">
+              <button
+                type="button"
+                className="btn btn-secondary"
+                onClick={this.openInitializeValueModal}
+                disabled={adminAppContainer.state.retrieveError != null}
+              >
+                {t('admin:app_setting.initialize_mail_settings')}
+              </button>
+            </div>
           </div>
           </div>
         </div>
         </div>
+
+
         <Modal isOpen={this.state.isInitializeValueModalOpen} toggle={this.closeInitializeValueModal} className="initialize-mail-settings">
         <Modal isOpen={this.state.isInitializeValueModalOpen} toggle={this.closeInitializeValueModal} className="initialize-mail-settings">
           <ModalHeader tag="h4" toggle={this.closeInitializeValueModal} className="bg-danger text-light">
           <ModalHeader tag="h4" toggle={this.closeInitializeValueModal} className="bg-danger text-light">
             {t('admin:app_setting.initialize_mail_modal_header')}
             {t('admin:app_setting.initialize_mail_modal_header')}

+ 1 - 1
src/client/js/components/Admin/ImportData/ImportDataPageContents.jsx

@@ -189,7 +189,7 @@ class ImportDataPageContents extends React.Component {
                   className="form-control"
                   className="form-control"
                   type="password"
                   type="password"
                   name="qiitaAccessToken"
                   name="qiitaAccessToken"
-                  value={adminImportContainer.stateqiitaAccessToken}
+                  value={adminImportContainer.state.qiitaAccessToken}
                   onChange={adminImportContainer.handleInputValue}
                   onChange={adminImportContainer.handleInputValue}
                 />
                 />
               </div>
               </div>

+ 13 - 0
src/client/js/services/AdminAppContainer.js

@@ -238,6 +238,19 @@ export default class AdminAppContainer extends Container {
     return siteUrlSettingParams;
     return siteUrlSettingParams;
   }
   }
 
 
+  /**
+   * Update from adress
+   * @memberOf AdminAppContainer
+   * @return {Array} Appearance
+   */
+  async updateFromAdressHandler() {
+    const response = await this.appContainer.apiv3.put('/app-settings/from-address', {
+      fromAddress: this.state.fromAddress,
+    });
+    const { mailSettingParams } = response.data;
+    return mailSettingParams;
+  }
+
   /**
   /**
    * Update mail setting
    * Update mail setting
    * @memberOf AdminAppContainer
    * @memberOf AdminAppContainer

+ 2 - 2
src/client/js/services/PageHistoryContainer.js

@@ -55,7 +55,7 @@ export default class PageHistoryContainer extends Container {
       return;
       return;
     }
     }
 
 
-    const res = await this.appContainer.apiv3Get('/revisions/list', { pageId, share_link_id: shareLinkId, selectedPage });
+    const res = await this.appContainer.apiv3Get('/revisions/list', { pageId, shareLinkId, selectedPage });
     const rev = res.data.docs;
     const rev = res.data.docs;
 
 
     // set Pagination state
     // set Pagination state
@@ -138,7 +138,7 @@ export default class PageHistoryContainer extends Container {
     }
     }
 
 
     try {
     try {
-      const res = await this.appContainer.apiv3Get(`/revisions/${revision._id}`, { pageId, share_link_id: shareLinkId });
+      const res = await this.appContainer.apiv3Get(`/revisions/${revision._id}`, { pageId, shareLinkId });
       this.setState({
       this.setState({
         revisions: this.state.revisions.map((rev) => {
         revisions: this.state.revisions.map((rev) => {
           // comparing ObjectId
           // comparing ObjectId

+ 2 - 2
src/server/middlewares/certify-shared-page.js

@@ -5,8 +5,8 @@ const logger = loggerFactory('growi:middleware:certify-shared-page');
 module.exports = (crowi) => {
 module.exports = (crowi) => {
 
 
   return async(req, res, next) => {
   return async(req, res, next) => {
-    const pageId = req.query.page_id || req.body.page_id || null;
-    const shareLinkId = req.query.share_link_id || req.body.share_link_id || null;
+    const pageId = req.query.pageId || req.body.pageId || null;
+    const shareLinkId = req.query.shareLinkId || req.body.shareLinkId || null;
     if (pageId == null || shareLinkId == null) {
     if (pageId == null || shareLinkId == null) {
       return next();
       return next();
     }
     }

+ 1 - 1
src/server/models/user.js

@@ -20,7 +20,7 @@ module.exports = function(crowi) {
   const STATUS_DELETED = 4;
   const STATUS_DELETED = 4;
   const STATUS_INVITED = 5;
   const STATUS_INVITED = 5;
   const USER_PUBLIC_FIELDS = '_id image isEmailPublished isGravatarEnabled googleId name username email introduction'
   const USER_PUBLIC_FIELDS = '_id image isEmailPublished isGravatarEnabled googleId name username email introduction'
-  + 'status lang createdAt lastLoginAt admin imageUrlCached';
+  + ' status lang createdAt lastLoginAt admin imageUrlCached';
 
 
   const PAGE_ITEMS = 50;
   const PAGE_ITEMS = 50;
 
 

+ 53 - 7
src/server/routes/apiv3/app-settings.js

@@ -50,13 +50,17 @@ const ErrorV3 = require('../../models/vo/error-apiv3');
  *          envSiteUrl:
  *          envSiteUrl:
  *            type: string
  *            type: string
  *            description: environment variable 'APP_SITE_URL'
  *            description: environment variable 'APP_SITE_URL'
- *      MailSettingParams:
+ *      FromAddress:
  *        description: MailSettingParams
  *        description: MailSettingParams
  *        type: object
  *        type: object
  *        properties:
  *        properties:
  *          fromAddress:
  *          fromAddress:
  *            type: string
  *            type: string
  *            description: e-mail address used as from address of mail which sent from GROWI app
  *            description: e-mail address used as from address of mail which sent from GROWI app
+ *      MailSettingParams:
+ *        description: MailSettingParams
+ *        type: object
+ *        properties:
  *          smtpHost:
  *          smtpHost:
  *            type: string
  *            type: string
  *            description: host name of client's smtp server
  *            description: host name of client's smtp server
@@ -115,8 +119,10 @@ module.exports = (crowi) => {
     siteUrlSetting: [
     siteUrlSetting: [
       body('siteUrl').trim().matches(/^(https?:\/\/[^/]+|)$/).isURL({ require_tld: false }),
       body('siteUrl').trim().matches(/^(https?:\/\/[^/]+|)$/).isURL({ require_tld: false }),
     ],
     ],
-    mailSetting: [
+    fromAddress: [
       body('fromAddress').trim().isEmail(),
       body('fromAddress').trim().isEmail(),
+    ],
+    mailSetting: [
       body('smtpHost').trim(),
       body('smtpHost').trim(),
       body('smtpPort').trim().isPort(),
       body('smtpPort').trim().isPort(),
       body('smtpUser').trim(),
       body('smtpUser').trim(),
@@ -292,7 +298,12 @@ module.exports = (crowi) => {
    * validate mail setting send test mail
    * validate mail setting send test mail
    */
    */
   async function validateMailSetting(req) {
   async function validateMailSetting(req) {
-    const { mailService } = crowi;
+    const { configManager, mailService } = crowi;
+    const fromAddress = configManager.getConfig('crowi', 'mail:from');
+    if (fromAddress == null) {
+      throw Error('fromAddress is not setup');
+    }
+
     const option = {
     const option = {
       host: req.body.smtpHost,
       host: req.body.smtpHost,
       port: req.body.smtpPort,
       port: req.body.smtpPort,
@@ -311,7 +322,7 @@ module.exports = (crowi) => {
     debug('mailer setup for validate SMTP setting', smtpClient);
     debug('mailer setup for validate SMTP setting', smtpClient);
 
 
     const mailOptions = {
     const mailOptions = {
-      from: req.body.fromAddress,
+      from: fromAddress,
       to: req.user.email,
       to: req.user.email,
       subject: 'Wiki管理設定のアップデートによるメール通知',
       subject: 'Wiki管理設定のアップデートによるメール通知',
       text: 'このメールは、WikiのSMTP設定のアップデートにより送信されています。',
       text: 'このメールは、WikiのSMTP設定のアップデートにより送信されています。',
@@ -333,7 +344,6 @@ module.exports = (crowi) => {
     mailService.publishUpdatedMessage();
     mailService.publishUpdatedMessage();
 
 
     return {
     return {
-      fromAddress: configManager.getConfig('crowi', 'mail:from'),
       smtpHost: configManager.getConfig('crowi', 'mail:smtpHost'),
       smtpHost: configManager.getConfig('crowi', 'mail:smtpHost'),
       smtpPort: configManager.getConfig('crowi', 'mail:smtpPort'),
       smtpPort: configManager.getConfig('crowi', 'mail:smtpPort'),
       smtpUser: configManager.getConfig('crowi', 'mail:smtpUser'),
       smtpUser: configManager.getConfig('crowi', 'mail:smtpUser'),
@@ -341,6 +351,44 @@ module.exports = (crowi) => {
     };
     };
   };
   };
 
 
+  /**
+   * @swagger
+   *
+   *    /app-settings/from-address:
+   *      put:
+   *        tags: [AppSettings]
+   *        operationId: updateAppSettingFromAddress
+   *        summary: /app-settings/from-address
+   *        description: Update from address
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/FromAddress'
+   *        responses:
+   *          200:
+   *            description: Succeeded to update from adress
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/FromAddress'
+   */
+  router.put('/from-address', loginRequiredStrictly, adminRequired, csrf, validator.fromAddress, apiV3FormValidator, async(req, res) => {
+
+    try {
+      const mailSettingParams = await updateMailSettinConfig({ 'mail:from': req.body.fromAddress });
+
+      return res.apiv3({ mailSettingParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating from adress';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-from-adress-failed'));
+    }
+
+  });
+
   /**
   /**
    * @swagger
    * @swagger
    *
    *
@@ -377,7 +425,6 @@ module.exports = (crowi) => {
 
 
 
 
     const requestMailSettingParams = {
     const requestMailSettingParams = {
-      'mail:from': req.body.fromAddress,
       'mail:smtpHost': req.body.smtpHost,
       'mail:smtpHost': req.body.smtpHost,
       'mail:smtpPort': req.body.smtpPort,
       'mail:smtpPort': req.body.smtpPort,
       'mail:smtpUser': req.body.smtpUser,
       'mail:smtpUser': req.body.smtpUser,
@@ -420,7 +467,6 @@ module.exports = (crowi) => {
    */
    */
   router.delete('/mail-setting', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
   router.delete('/mail-setting', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
     const requestMailSettingParams = {
     const requestMailSettingParams = {
-      'mail:from': null,
       'mail:smtpHost': null,
       'mail:smtpHost': null,
       'mail:smtpPort': null,
       'mail:smtpPort': null,
       'mail:smtpUser': null,
       'mail:smtpUser': null,

+ 4 - 1
src/server/routes/attachment.js

@@ -228,7 +228,10 @@ module.exports = function(crowi, app) {
     }
     }
     // reference
     // reference
     else {
     else {
-      res.set('Content-Type', attachment.fileFormat);
+      res.set({
+        'Content-Type': attachment.fileFormat,
+        'Content-Security-Policy': "script-src 'unsafe-hashes'",
+      });
     }
     }
   }
   }
 
 

Разница между файлами не показана из-за своего большого размера
+ 396 - 215
yarn.lock


Некоторые файлы не были показаны из-за большого количества измененных файлов