mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-09 22:24:05 -08:00
feat(core): Rate limit forgot password endpoint (#7604)
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <netroy@users.noreply.github.com>
This commit is contained in:
parent
acec9bad71
commit
5790e251b8
|
@ -129,6 +129,7 @@
|
|||
"express-handlebars": "^7.0.2",
|
||||
"express-openapi-validator": "^4.13.6",
|
||||
"express-prom-bundle": "^6.6.0",
|
||||
"express-rate-limit": "^7.1.3",
|
||||
"fast-glob": "^3.2.5",
|
||||
"flatted": "^3.2.4",
|
||||
"formidable": "^3.5.0",
|
||||
|
|
|
@ -55,6 +55,9 @@ export abstract class AbstractServer {
|
|||
this.app = express();
|
||||
this.app.disable('x-powered-by');
|
||||
|
||||
const proxyHops = config.getEnv('proxy_hops');
|
||||
if (proxyHops > 0) this.app.set('trust proxy', proxyHops);
|
||||
|
||||
this.protocol = config.getEnv('protocol');
|
||||
this.sslKey = config.getEnv('ssl_key');
|
||||
this.sslCert = config.getEnv('ssl_cert');
|
||||
|
|
|
@ -1344,4 +1344,11 @@ export const schema = {
|
|||
env: 'N8N_LEADER_SELECTION_CHECK_INTERVAL',
|
||||
},
|
||||
},
|
||||
|
||||
proxy_hops: {
|
||||
format: Number,
|
||||
default: 0,
|
||||
env: 'N8N_PROXY_HOPS',
|
||||
doc: 'Number of reverse-proxies n8n is running behind',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -24,12 +24,18 @@ import { isSamlCurrentAuthenticationMethod } from '@/sso/ssoHelpers';
|
|||
import { UserService } from '@/services/user.service';
|
||||
import { License } from '@/License';
|
||||
import { Container } from 'typedi';
|
||||
import { RESPONSE_ERROR_MESSAGES } from '@/constants';
|
||||
import { RESPONSE_ERROR_MESSAGES, inTest } from '@/constants';
|
||||
import { TokenExpiredError } from 'jsonwebtoken';
|
||||
import type { JwtPayload } from '@/services/jwt.service';
|
||||
import { JwtService } from '@/services/jwt.service';
|
||||
import { MfaService } from '@/Mfa/mfa.service';
|
||||
import { Logger } from '@/Logger';
|
||||
import { rateLimit } from 'express-rate-limit';
|
||||
|
||||
const throttle = rateLimit({
|
||||
windowMs: 5 * 60 * 1000, // 5 minutes
|
||||
limit: 5, // Limit each IP to 5 requests per `window` (here, per 5 minutes).
|
||||
});
|
||||
|
||||
@RestController()
|
||||
export class PasswordResetController {
|
||||
|
@ -46,7 +52,9 @@ export class PasswordResetController {
|
|||
/**
|
||||
* Send a password reset email.
|
||||
*/
|
||||
@Post('/forgot-password')
|
||||
@Post('/forgot-password', {
|
||||
middlewares: !inTest ? [throttle] : [],
|
||||
})
|
||||
async forgotPassword(req: PasswordResetRequest.Email) {
|
||||
if (!this.mailer.isEmailSetUp) {
|
||||
this.logger.debug(
|
||||
|
|
|
@ -660,6 +660,7 @@
|
|||
"forgotPassword.sendingEmailError": "Problem sending email",
|
||||
"forgotPassword.ldapUserPasswordResetUnavailable": "Please contact your LDAP administrator to reset your password",
|
||||
"forgotPassword.smtpErrorContactAdministrator": "Please contact your administrator (problem with your SMTP setup)",
|
||||
"forgotPassword.tooManyRequests": "You’ve reached the password reset limit. Please try again in a few minutes.",
|
||||
"forms.resourceFiltersDropdown.filters": "Filters",
|
||||
"forms.resourceFiltersDropdown.ownedBy": "Owned by",
|
||||
"forms.resourceFiltersDropdown.sharedWith": "Shared with",
|
||||
|
|
|
@ -88,14 +88,20 @@ export default defineComponent({
|
|||
});
|
||||
} catch (error) {
|
||||
let message = this.$locale.baseText('forgotPassword.smtpErrorContactAdministrator');
|
||||
if (error.httpStatusCode === 422) {
|
||||
message = this.$locale.baseText(error.message);
|
||||
if (error.isAxiosError) {
|
||||
const { status } = error.response;
|
||||
if (status === 429) {
|
||||
message = this.$locale.baseText('forgotPassword.tooManyRequests');
|
||||
} else if (error.httpStatusCode === 422) {
|
||||
message = this.$locale.baseText(error.message);
|
||||
}
|
||||
|
||||
this.showMessage({
|
||||
type: 'error',
|
||||
title: this.$locale.baseText('forgotPassword.sendingEmailError'),
|
||||
message,
|
||||
});
|
||||
}
|
||||
this.showMessage({
|
||||
type: 'error',
|
||||
title: this.$locale.baseText('forgotPassword.sendingEmailError'),
|
||||
message,
|
||||
});
|
||||
}
|
||||
this.loading = false;
|
||||
},
|
||||
|
|
|
@ -284,6 +284,9 @@ importers:
|
|||
express-prom-bundle:
|
||||
specifier: ^6.6.0
|
||||
version: 6.6.0(prom-client@13.2.0)
|
||||
express-rate-limit:
|
||||
specifier: ^7.1.3
|
||||
version: 7.1.3(express@4.18.2)
|
||||
fast-glob:
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.12
|
||||
|
@ -9641,7 +9644,7 @@ packages:
|
|||
/axios@0.21.4:
|
||||
resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2(debug@4.3.4)
|
||||
follow-redirects: 1.15.2(debug@3.2.7)
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
@ -9670,11 +9673,12 @@ packages:
|
|||
form-data: 4.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: true
|
||||
|
||||
/axios@1.4.0:
|
||||
resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.2(debug@4.3.4)
|
||||
follow-redirects: 1.15.2(debug@3.2.7)
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
|
@ -12772,6 +12776,15 @@ packages:
|
|||
url-value-parser: 2.2.0
|
||||
dev: false
|
||||
|
||||
/express-rate-limit@7.1.3(express@4.18.2):
|
||||
resolution: {integrity: sha512-BDes6WeNYSGRRGQU8QDNwUnwqaBro28HN/TTweM3RlxXRHDld8RLoH7tbfCxAc0hamQyn6aL0KrfR45+ZxknYg==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
express: 4 || 5 || ^5.0.0-beta.1
|
||||
dependencies:
|
||||
express: 4.18.2
|
||||
dev: false
|
||||
|
||||
/express@4.18.2:
|
||||
resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
|
@ -13236,6 +13249,7 @@ packages:
|
|||
optional: true
|
||||
dependencies:
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
dev: true
|
||||
|
||||
/for-each@0.3.3:
|
||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||
|
@ -18476,7 +18490,7 @@ packages:
|
|||
resolution: {integrity: sha512-aXYe/D+28kF63W8Cz53t09ypEORz+ULeDCahdAqhVrRm2scbOXFbtnn0GGhvMpYe45grepLKuwui9KxrZ2ZuMw==}
|
||||
engines: {node: '>=14.17.0'}
|
||||
dependencies:
|
||||
axios: 0.27.2(debug@4.3.4)
|
||||
axios: 0.27.2(debug@3.2.7)
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
dev: false
|
||||
|
|
Loading…
Reference in a new issue