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

Merge pull request #5899 from weseek/feat/environmentVar-passwordLength

feat: Set the min length of passwords by environment variable
Yuki Takei 3 лет назад
Родитель
Сommit
ca4538c1ab

+ 1 - 1
packages/app/resource/locales/en_US/translation.json

@@ -212,7 +212,7 @@
     },
     },
     "form_help": {
     "form_help": {
       "email": "You must have email address which listed below to sign up to this wiki.",
       "email": "You must have email address which listed below to sign up to this wiki.",
-      "password": "Your password must be at least 8 characters long.",
+      "password": "Your password must be at least {{target}} characters long.",
       "user_id": "The URL of pages you create will contain your User ID. Your User ID can consist of letters, numbers, and some symbols."
       "user_id": "The URL of pages you create will contain your User ID. Your User ID can consist of letters, numbers, and some symbols."
     }
     }
   },
   },

+ 1 - 1
packages/app/resource/locales/ja_JP/translation.json

@@ -214,7 +214,7 @@
     },
     },
     "form_help": {
     "form_help": {
       "email": "この Wiki では以下のメールアドレスのみ登録可能です。",
       "email": "この Wiki では以下のメールアドレスのみ登録可能です。",
-      "password": "パスワードには、8文字以上の半角英数字または記号等を設定してください。",
+      "password": "パスワードには、{{target}}文字以上の半角英数字または記号等を設定してください。",
       "user_id": "ユーザーIDは、ユーザーページのURLなどに利用されます。半角英数字と一部の記号のみ利用できます。"
       "user_id": "ユーザーIDは、ユーザーページのURLなどに利用されます。半角英数字と一部の記号のみ利用できます。"
     }
     }
   },
   },

+ 5 - 6
packages/app/src/components/Me/PasswordSettings.jsx

@@ -10,7 +10,6 @@ import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 import { withUnstatedContainers } from '../UnstatedUtils';
 
 
-
 class PasswordSettings extends React.Component {
 class PasswordSettings extends React.Component {
 
 
   constructor() {
   constructor() {
@@ -22,6 +21,7 @@ class PasswordSettings extends React.Component {
       newPassword: '',
       newPassword: '',
       newPasswordConfirm: '',
       newPasswordConfirm: '',
       isPasswordSet: false,
       isPasswordSet: false,
+      minPasswordLength: null,
     };
     };
 
 
     this.onClickSubmit = this.onClickSubmit.bind(this);
     this.onClickSubmit = this.onClickSubmit.bind(this);
@@ -32,8 +32,8 @@ class PasswordSettings extends React.Component {
   async componentDidMount() {
   async componentDidMount() {
     try {
     try {
       const res = await apiv3Get('/personal-setting/is-password-set');
       const res = await apiv3Get('/personal-setting/is-password-set');
-      const { isPasswordSet } = res.data;
-      this.setState({ isPasswordSet });
+      const { isPasswordSet, minPasswordLength } = res.data;
+      this.setState({ isPasswordSet, minPasswordLength });
     }
     }
     catch (err) {
     catch (err) {
       toastError(err);
       toastError(err);
@@ -74,9 +74,8 @@ class PasswordSettings extends React.Component {
 
 
   render() {
   render() {
     const { t } = this.props;
     const { t } = this.props;
-    const { newPassword, newPasswordConfirm } = this.state;
+    const { newPassword, newPasswordConfirm, minPasswordLength } = this.state;
     const isIncorrectConfirmPassword = (newPassword !== newPasswordConfirm);
     const isIncorrectConfirmPassword = (newPassword !== newPasswordConfirm);
-
     if (this.state.retrieveError != null) {
     if (this.state.retrieveError != null) {
       throw new Error(this.state.retrieveError.message);
       throw new Error(this.state.retrieveError.message);
     }
     }
@@ -131,7 +130,7 @@ class PasswordSettings extends React.Component {
               onChange={(e) => { this.onChangeNewPasswordConfirm(e.target.value) }}
               onChange={(e) => { this.onChangeNewPasswordConfirm(e.target.value) }}
             />
             />
 
 
-            <p className="form-text text-muted">{t('page_register.form_help.password') }</p>
+            <p className="form-text text-muted">{t('page_register.form_help.password', { target: minPasswordLength }) }</p>
           </div>
           </div>
         </div>
         </div>
 
 

+ 5 - 2
packages/app/src/server/routes/apiv3/forgot-password.js

@@ -10,6 +10,7 @@ import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
 import httpErrorHandler from '../../middlewares/http-error-handler';
 import httpErrorHandler from '../../middlewares/http-error-handler';
 import { checkForgotPasswordEnabledMiddlewareFactory } from '../forgot-password';
 import { checkForgotPasswordEnabledMiddlewareFactory } from '../forgot-password';
 
 
+
 const logger = loggerFactory('growi:routes:apiv3:forgotPassword'); // eslint-disable-line no-unused-vars
 const logger = loggerFactory('growi:routes:apiv3:forgotPassword'); // eslint-disable-line no-unused-vars
 
 
 const express = require('express');
 const express = require('express');
@@ -25,11 +26,13 @@ module.exports = (crowi) => {
   const path = require('path');
   const path = require('path');
   const csrf = require('../../middlewares/csrf')(crowi);
   const csrf = require('../../middlewares/csrf')(crowi);
 
 
+  const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
+
   const validator = {
   const validator = {
     password: [
     password: [
       body('newPassword').isString().not().isEmpty()
       body('newPassword').isString().not().isEmpty()
-        .isLength({ min: 8 })
-        .withMessage('password must be at least 8 characters long'),
+        .isLength({ min: minPasswordLength })
+        .withMessage(`password must be at least ${minPasswordLength} characters long`),
       // checking if password confirmation matches password
       // checking if password confirmation matches password
       body('newPasswordConfirm').isString().not().isEmpty()
       body('newPasswordConfirm').isString().not().isEmpty()
         .custom((value, { req }) => {
         .custom((value, { req }) => {

+ 6 - 4
packages/app/src/server/routes/apiv3/personal-setting.js

@@ -72,6 +72,8 @@ module.exports = (crowi) => {
 
 
   const { User, ExternalAccount } = crowi.models;
   const { User, ExternalAccount } = crowi.models;
 
 
+  const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
+
   const validator = {
   const validator = {
     personal: [
     personal: [
       body('name').isString().not().isEmpty(),
       body('name').isString().not().isEmpty(),
@@ -91,8 +93,8 @@ module.exports = (crowi) => {
     password: [
     password: [
       body('oldPassword').isString(),
       body('oldPassword').isString(),
       body('newPassword').isString().not().isEmpty()
       body('newPassword').isString().not().isEmpty()
-        .isLength({ min: 8 })
-        .withMessage('password must be at least 8 characters long'),
+        .isLength({ min: minPasswordLength })
+        .withMessage(`password must be at least ${minPasswordLength} characters long`),
       body('newPasswordConfirm').isString().not().isEmpty()
       body('newPasswordConfirm').isString().not().isEmpty()
         .custom((value, { req }) => {
         .custom((value, { req }) => {
           return (value === req.body.newPassword);
           return (value === req.body.newPassword);
@@ -146,7 +148,6 @@ module.exports = (crowi) => {
    */
    */
   router.get('/', accessTokenParser, loginRequiredStrictly, async(req, res) => {
   router.get('/', accessTokenParser, loginRequiredStrictly, async(req, res) => {
     const { username } = req.user;
     const { username } = req.user;
-
     try {
     try {
       const user = await User.findUserByUsername(username);
       const user = await User.findUserByUsername(username);
 
 
@@ -189,7 +190,8 @@ module.exports = (crowi) => {
     try {
     try {
       const user = await User.findUserByUsername(username);
       const user = await User.findUserByUsername(username);
       const isPasswordSet = user.isPasswordSet();
       const isPasswordSet = user.isPasswordSet();
-      return res.apiv3({ isPasswordSet });
+      const minPasswordLength = crowi.configManager.getConfig('crowi', 'app:minPasswordLength');
+      return res.apiv3({ isPasswordSet, minPasswordLength });
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);

+ 7 - 1
packages/app/src/server/service/config-loader.ts

@@ -1,6 +1,6 @@
+import { envUtils } from '@growi/core';
 import { parseISO } from 'date-fns';
 import { parseISO } from 'date-fns';
 
 
-import { envUtils } from '@growi/core';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
 
 
@@ -610,6 +610,12 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type:    ValueType.STRING,
     type:    ValueType.STRING,
     default: null,
     default: null,
   },
   },
+  MIN_PASSWORD_LENGTH: {
+    ns: 'crowi',
+    key: 'app:minPasswordLength',
+    type: ValueType.NUMBER,
+    default: 8,
+  },
 };
 };