diff --git a/Dockerfile b/Dockerfile index a6998a868d5414e7fc04aa561d8663913aab0cf9..15284c86949ccbbfd011f190afd62dc611522980 100644 --- a/Dockerfile +++ b/Dockerfile @@ -108,6 +108,7 @@ RUN patch -u ${BASE_DIR}/lib/private/L10N/Factory.php -i ${TMP_PATCH_DIR}/032-se # UserConfigChangedEvent Ref: https://github.com/nextcloud/server/pull/42039 RUN cd ${BASE_DIR} && patch -p1 < ${TMP_PATCH_DIR}/036-user-config-change-event.patch RUN patch -u ${BASE_DIR}/custom_apps/integration_google/lib/Service/GoogleDriveAPIService.php -i ${TMP_PATCH_DIR}/039-fix-slow-google-import-job.patch +RUN cd ${BASE_DIR} && patch -p1 < ${TMP_PATCH_DIR}/040-password-length-rules.patch RUN rm -rf ${TMP_PATCH_DIR} diff --git a/patches/040-password-length-rules.patch b/patches/040-password-length-rules.patch new file mode 100644 index 0000000000000000000000000000000000000000..7783eca42c71d723402d6d20414b026eacbbac6c --- /dev/null +++ b/patches/040-password-length-rules.patch @@ -0,0 +1,150 @@ +Subject: [PATCH] New password length rules for change and forgot password + +Enforce minimum length of 12 and maximum length of 128 for personal +password change and lost-password reset flows (frontend and backend). + +--- ./apps/settings/src/components/PasswordSection.vue ++++ ./apps/settings/src/components/PasswordSection.vue-new +@@ -16,7 +16,8 @@ + ++ :disabled="newPass.length < 12 || newPass.length > 128 || oldPass.length === 0"> + {{ t('settings', 'Change password') }} + + +@@ -54,6 +55,14 @@ + }, + methods: { + changePassword() { ++ if (this.newPass.length < 12) { ++ showError(t('settings', 'Password must be at least 12 characters long')) ++ return ++ } ++ if (this.newPass.length > 128) { ++ showError(t('settings', 'Password must not exceed 128 characters')) ++ return ++ } + axios.post(generateUrl('/settings/personal/changepassword'), { + oldpassword: this.oldPass, + newpassword: this.newPass, +--- ./apps/settings/lib/Controller/ChangePasswordController.php ++++ ./apps/settings/lib/Controller/ChangePasswordController.php-new +@@ -66,7 +66,7 @@ + } + + try { +- if ($newpassword === null || strlen($newpassword) > IUserManager::MAX_PASSWORD_LENGTH || $user->setPassword($newpassword) === false) { ++ if ($newpassword === null) { + return new JSONResponse([ + 'status' => 'error', + 'data' => [ +@@ -74,6 +74,31 @@ + ], + ]); + } ++ $newPasswordLength = strlen($newpassword); ++ if ($newPasswordLength < 12) { ++ return new JSONResponse([ ++ 'status' => 'error', ++ 'data' => [ ++ 'message' => $this->l->t('Password must be at least 12 characters long'), ++ ], ++ ]); ++ } ++ if ($newPasswordLength > 128) { ++ return new JSONResponse([ ++ 'status' => 'error', ++ 'data' => [ ++ 'message' => $this->l->t('Password must not exceed 128 characters'), ++ ], ++ ]); ++ } ++ if ($user->setPassword($newpassword) === false) { ++ return new JSONResponse([ ++ 'status' => 'error', ++ 'data' => [ ++ 'message' => $this->l->t('Unable to change personal password'), ++ ], ++ ]); ++ } + // password policy app throws exception + } catch (HintException $e) { + return new JSONResponse([ +@@ -115,11 +140,14 @@ + ]); + } + +- if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) { ++ $passwordLength = strlen($password); ++ if ($passwordLength < 12 || $passwordLength > 128) { + return new JSONResponse([ + 'status' => 'error', + 'data' => [ +- 'message' => $this->l->t('Unable to change password. Password too long.'), ++ 'message' => $passwordLength < 12 ++ ? $this->l->t('Password must be at least 12 characters long') ++ : $this->l->t('Password must not exceed 128 characters'), + ], + ]); + } +--- ./core/src/components/login/UpdatePassword.vue ++++ ./core/src/components/login/UpdatePassword.vue-new +@@ -12,6 +12,8 @@ + v-model="password" + type="password" + name="password" ++ minlength="12" ++ maxlength="128" + autocomplete="new-password" + autocapitalize="none" + spellcheck="false" +@@ -84,6 +86,19 @@ + this.error = false + this.message = '' + ++ if (this.password.length < 12) { ++ this.error = true ++ this.message = t('core', 'Password must be at least 12 characters long') ++ this.loading = false ++ return ++ } ++ if (this.password.length > 128) { ++ this.error = true ++ this.message = t('core', 'Password must not exceed 128 characters') ++ this.loading = false ++ return ++ } ++ + try { + const { data } = await Axios.post(this.resetPasswordTarget, { + password: this.password, +--- ./core/Controller/LostController.php ++++ ./core/Controller/LostController.php-new +@@ -204,9 +204,13 @@ + $this->eventDispatcher->dispatchTyped(new BeforePasswordResetEvent($user, $password)); + \OC_Hook::emit('\OC\Core\LostPassword\Controller\LostController', 'pre_passwordReset', ['uid' => $userId, 'password' => $password]); + +- if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) { +- throw new HintException('Password too long', $this->l10n->t('Password is too long. Maximum allowed length is 469 characters.')); ++ $passwordLength = strlen($password); ++ if ($passwordLength < 12) { ++ throw new HintException('Password too short', $this->l10n->t('Password must be at least 12 characters long')); + } ++ if ($passwordLength > 128) { ++ throw new HintException('Password too long', $this->l10n->t('Password must not exceed 128 characters')); ++ } + + if (!$user->setPassword($password)) { + throw new Exception();