#1928 Customizable password reset lifetime
authorNassim Bounouas <nassim.bounouas@gmail.com>
Sat, 22 Jun 2019 19:19:16 +0000 (21:19 +0200)
committerNassim Bounouas <nassim.bounouas@gmail.com>
Sat, 22 Jun 2019 19:19:16 +0000 (21:19 +0200)
client/src/app/core/server/server.service.ts
client/src/app/login/login.component.ts
config/default.yaml
config/production.yaml.example
server/controllers/api/config.ts
server/initializers/config.ts
server/initializers/constants.ts
server/lib/emailer.ts
server/lib/redis.ts
shared/models/server/server-config.model.ts

index 689f25a405c980415a3adbd67c28f9d52841dd5e..fe0786f4af7761c27b368d7214079c1af42b3288 100644 (file)
@@ -83,7 +83,8 @@ export class ServerService {
     },
     user: {
       videoQuota: -1,
-      videoQuotaDaily: -1
+      videoQuotaDaily: -1,
+      resetPasswordLifetime: 5
     },
     import: {
       videos: {
index dc10de325f4d026770c271aa9c6f3518d345e9b4..2ba47dea0a6cce0c538f023511d68fd2c2739cff 100644 (file)
@@ -78,7 +78,7 @@ export class LoginComponent extends FormReactive implements OnInit {
       .subscribe(
         () => {
           const message = this.i18n(
-            'An email with the reset password instructions will be sent to {{email}}. The link will expire within 5 minutes.',
+            `An email with the reset password instructions will be sent to {{email}}. The link will expire within ${this.getResetPasswordLifetime()} minutes.`,
             { email: this.forgotPasswordEmail }
           )
           this.notifier.success(message)
@@ -96,4 +96,8 @@ export class LoginComponent extends FormReactive implements OnInit {
   hideForgotPasswordModal () {
     this.openedForgotPasswordModal.close()
   }
+
+  getResetPasswordLifetime () {
+    return this.serverService.getConfig().user.resetPasswordLifetime
+  }
 }
index a213d5b0a768fbd6983ee2f65095ac187969e828..7d5f75def3de1ec94a57a5cf92437f77dd67a7b9 100644 (file)
@@ -174,6 +174,7 @@ user:
   # -1 == unlimited
   video_quota: -1
   video_quota_daily: -1
+  password_reset_lifetime: 15 # Minutes before password reset link expiration
 
 # If enabled, the video will be transcoded to mp4 (x264) with "faststart" flag
 # In addition, if some resolutions are enabled the mp4 video file will be transcoded to these new resolutions.
index cdf6136d85b21b6d6f7c8bda479f8c1f069187cd..8ac8eaf70bd02cf68400328386583e92d7b6774a 100644 (file)
@@ -188,6 +188,7 @@ user:
   # -1 == unlimited
   video_quota: -1
   video_quota_daily: -1
+  password_reset_lifetime: 5 # Minutes before password reset link expiration
 
 # If enabled, the video will be transcoded to mp4 (x264) with "faststart" flag
 # In addition, if some resolutions are enabled the mp4 video file will be transcoded to these new resolutions.
index 1d12f701b2aaeff4025a00721da482d202cb9486..c83bd354e877466a6939e699965fc34e15f130b7 100644 (file)
@@ -131,7 +131,8 @@ async function getConfig (req: express.Request, res: express.Response) {
     },
     user: {
       videoQuota: CONFIG.USER.VIDEO_QUOTA,
-      videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
+      videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY,
+      resetPasswordLifetime: CONFIG.USER.USER_PASSWORD_RESET_LIFETIME
     },
     trending: {
       videos: {
index bb278ba43d44c1a3f1e1d5d49d34963925cfbce9..b6bca1ee565e26be7ad94c98549b20d63b48fb12 100644 (file)
@@ -144,7 +144,8 @@ const CONFIG = {
   },
   USER: {
     get VIDEO_QUOTA () { return parseBytes(config.get<number>('user.video_quota')) },
-    get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) }
+    get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) },
+    get USER_PASSWORD_RESET_LIFETIME () { return parseBytes(config.get<number>('user.password_reset_lifetime')) }
   },
   TRANSCODING: {
     get ENABLED () { return config.get<boolean>('transcoding.enabled') },
index 500f8770ab4e5ced85f239f6fc35bf8526c66c0a..bca637128e09b66dd5a9c60021b2946961200627 100644 (file)
@@ -471,8 +471,6 @@ let PRIVATE_RSA_KEY_SIZE = 2048
 // Password encryption
 const BCRYPT_SALT_SIZE = 10
 
-const USER_PASSWORD_RESET_LIFETIME = 60000 * 5 // 5 minutes
-
 const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes
 
 const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = {
@@ -689,7 +687,6 @@ export {
   VIDEO_ABUSE_STATES,
   CACHE,
   JOB_REQUEST_TIMEOUT,
-  USER_PASSWORD_RESET_LIFETIME,
   MEMOIZE_TTL,
   USER_EMAIL_VERIFY_LIFETIME,
   OVERVIEWS,
index 540c36025f71bc123467bea68d75814d75b6830b..e3bbccaa392d086d75c9661fb697cb4adb82b36e 100644 (file)
@@ -350,7 +350,7 @@ class Emailer {
   addPasswordResetEmailJob (to: string, resetPasswordUrl: string) {
     const text = `Hi dear user,\n\n` +
       `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` +
-      `Please follow this link to reset it: ${resetPasswordUrl}  (the link will expire within 5 minutes)\n\n` +
+      `Please follow this link to reset it: ${resetPasswordUrl}  (the link will expire within ${CONFIG.USER.USER_PASSWORD_RESET_LIFETIME} minutes)\n\n` +
       `If you are not the person who initiated this request, please ignore this email.\n\n` +
       `Cheers,\n` +
       `${CONFIG.EMAIL.BODY.SIGNATURE}`
index f77d0b62c20ba22d3a92c01da5e097b7b35cf8c1..200a48c303f928906be4e3d33a59d9c2ba1e9577 100644 (file)
@@ -5,7 +5,6 @@ import { generateRandomString } from '../helpers/utils'
 import {
   CONTACT_FORM_LIFETIME,
   USER_EMAIL_VERIFY_LIFETIME,
-  USER_PASSWORD_RESET_LIFETIME,
   VIDEO_VIEW_LIFETIME,
   WEBSERVER
 } from '../initializers/constants'
@@ -68,6 +67,7 @@ class Redis {
   async setResetPasswordVerificationString (userId: number) {
     const generatedString = await generateRandomString(32)
 
+    const USER_PASSWORD_RESET_LIFETIME = CONFIG.USER.USER_PASSWORD_RESET_LIFETIME * 60000
     await this.setValue(this.generateResetPasswordKey(userId), generatedString, USER_PASSWORD_RESET_LIFETIME)
 
     return generatedString
index d937e9c05a2d39b1c8039697cde01c022bcfc350..3a7090eb19f29d818fe232dae7db7e840750c4d8 100644 (file)
@@ -90,6 +90,7 @@ export interface ServerConfig {
   user: {
     videoQuota: number
     videoQuotaDaily: number
+    resetPasswordLifetime: number
   }
 
   trending: {