@strapi/plugin-users-permissions 5.43.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/translations/cs.json +42 -5
- package/dist/admin/translations/cs.json.js +42 -5
- package/dist/admin/translations/cs.json.js.map +1 -1
- package/dist/admin/translations/cs.json.mjs +42 -5
- package/dist/admin/translations/cs.json.mjs.map +1 -1
- package/dist/server/_virtual/rateLimit.js +6 -0
- package/dist/server/_virtual/rateLimit.js.map +1 -0
- package/dist/server/_virtual/rateLimit.mjs +4 -0
- package/dist/server/_virtual/rateLimit.mjs.map +1 -0
- package/dist/server/middlewares/rateLimit.js +87 -18
- package/dist/server/middlewares/rateLimit.js.map +1 -1
- package/dist/server/middlewares/rateLimit.mjs +87 -18
- package/dist/server/middlewares/rateLimit.mjs.map +1 -1
- package/dist/server/routes/content-api/auth.js +3 -0
- package/dist/server/routes/content-api/auth.js.map +1 -1
- package/dist/server/routes/content-api/auth.mjs +3 -0
- package/dist/server/routes/content-api/auth.mjs.map +1 -1
- package/package.json +4 -4
- package/server/middlewares/rateLimit.js +91 -15
- package/server/routes/content-api/auth.js +1 -0
|
@@ -12,35 +12,72 @@
|
|
|
12
12
|
"EditForm.inputToggle.label.email-confirmation-redirection": "Adresa pro přesměrování",
|
|
13
13
|
"EditForm.inputToggle.label.email-reset-password": "Stránka pro obnovení hesla",
|
|
14
14
|
"EditForm.inputToggle.label.sign-up": "Povolit registrace",
|
|
15
|
+
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/email-confirmation-redirection",
|
|
16
|
+
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
|
|
17
|
+
"EditPage.form.roles": "Detaily role",
|
|
18
|
+
"Email.template.data.loaded": "E-mailové šablony byly načteny",
|
|
19
|
+
"Email.template.email_confirmation": "Potvrzení e-mailové adresy",
|
|
20
|
+
"Email.template.reset_password": "Obnovení hesla",
|
|
21
|
+
"Email.template.form.edit.label": "Upravit šablonu",
|
|
22
|
+
"Email.template.table.action.label": "akce",
|
|
23
|
+
"Email.template.table.icon.label": "ikona",
|
|
24
|
+
"Email.template.table.name.label": "název",
|
|
25
|
+
"Form.advancedSettings.data.loaded": "Data pokročilých nastavení byla načtena",
|
|
15
26
|
"HeaderNav.link.advancedSettings": "Pokročilá nastavení",
|
|
16
27
|
"HeaderNav.link.emailTemplates": "E-mailové šablony",
|
|
17
28
|
"HeaderNav.link.providers": "Poskytovatelé",
|
|
18
|
-
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro
|
|
29
|
+
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro plugin {name}.",
|
|
19
30
|
"Plugins.header.description": "Pouze akce spojené s adresou jsou vypsány níže.",
|
|
20
31
|
"Plugins.header.title": "Povolení",
|
|
21
|
-
"Policies.header.hint": "Vyberte akce aplikace, nebo akce
|
|
32
|
+
"Policies.header.hint": "Vyberte akce aplikace, nebo akce pluginu a klikněte na ikonku ozubeného kolečka pro zobrazení adresy s nimi spojenou.",
|
|
22
33
|
"Policies.header.title": "Pokročilá nastavení",
|
|
23
34
|
"PopUpForm.Email.email_templates.inputDescription": "Pokud si nejste jisti jak používat proměnné, {link}",
|
|
35
|
+
"PopUpForm.Email.link.documentation": "podívejte se do naší dokumentace.",
|
|
24
36
|
"PopUpForm.Email.options.from.email.label": "Odesilatelův e-mail",
|
|
25
37
|
"PopUpForm.Email.options.from.email.placeholder": "jannovak@gmail.com",
|
|
26
38
|
"PopUpForm.Email.options.from.name.label": "Jméno odesilatele",
|
|
27
39
|
"PopUpForm.Email.options.from.name.placeholder": "Jan Novák",
|
|
28
40
|
"PopUpForm.Email.options.message.label": "Zpráva",
|
|
29
41
|
"PopUpForm.Email.options.object.label": "Předmět",
|
|
42
|
+
"PopUpForm.Email.options.object.placeholder": "Potvrďte prosím svou e-mailovou adresu pro %APP_NAME%",
|
|
30
43
|
"PopUpForm.Email.options.response_email.label": "Response e-mail",
|
|
31
44
|
"PopUpForm.Email.options.response_email.placeholder": "jannovak@gmail.com",
|
|
32
|
-
"PopUpForm.Providers.enabled.description": "
|
|
45
|
+
"PopUpForm.Providers.enabled.description": "Pokud je zakázáno, uživatelé nebudou moci tohoto poskytovatele použít.",
|
|
33
46
|
"PopUpForm.Providers.enabled.label": "Povolit",
|
|
34
47
|
"PopUpForm.Providers.key.label": "Client ID",
|
|
35
48
|
"PopUpForm.Providers.key.placeholder": "TEXT",
|
|
36
49
|
"PopUpForm.Providers.redirectURL.front-end.label": "Adresa pro přesměrování na vaši front-end aplikaci",
|
|
50
|
+
"PopUpForm.Providers.redirectURL.label": "Adresa pro přesměrování, kterou je třeba přidat do konfigurace vaší aplikace {provider}",
|
|
37
51
|
"PopUpForm.Providers.secret.label": "Client Secret",
|
|
38
52
|
"PopUpForm.Providers.secret.placeholder": "TEXT",
|
|
39
53
|
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
|
|
40
54
|
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
|
|
41
55
|
"PopUpForm.header.edit.email-templates": "Upravit e-mailové šablony",
|
|
56
|
+
"PopUpForm.header.edit.providers": "Upravit poskytovatele",
|
|
57
|
+
"Providers.data.loaded": "Poskytovatelé byli načteni",
|
|
58
|
+
"Providers.status": "Stav",
|
|
59
|
+
"Roles.empty": "Zatím nemáte žádné role.",
|
|
60
|
+
"Roles.empty.search": "Hledání neodpovídají žádné role.",
|
|
61
|
+
"Settings.roles.deleted": "Role smazána",
|
|
62
|
+
"Settings.roles.edited": "Role upravena",
|
|
63
|
+
"Settings.section-label": "Plugin Users & Permissions",
|
|
64
|
+
"components.Input.error.validation.email": "Toto není platný e-mail",
|
|
65
|
+
"components.Input.error.validation.json": "Toto neodpovídá formátu JSON",
|
|
66
|
+
"components.Input.error.validation.max": "Hodnota je příliš vysoká.",
|
|
67
|
+
"components.Input.error.validation.maxLength": "Hodnota je příliš dlouhá.",
|
|
68
|
+
"components.Input.error.validation.min": "Hodnota je příliš nízká.",
|
|
69
|
+
"components.Input.error.validation.minLength": "Hodnota je příliš krátká.",
|
|
70
|
+
"components.Input.error.validation.minSupMax": "Nemůže být vyšší",
|
|
71
|
+
"components.Input.error.validation.regex": "Hodnota neodpovídá regulárnímu výrazu.",
|
|
72
|
+
"components.Input.error.validation.required": "Tato hodnota je povinná.",
|
|
73
|
+
"components.Input.error.validation.unique": "Tato hodnota už je použita.",
|
|
42
74
|
"notification.success.submit": "Nastavení bylo aktualizování",
|
|
43
|
-
"
|
|
75
|
+
"page.title": "Nastavení - Role",
|
|
76
|
+
"plugin.description.long": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT. Tento plugin obsahuje ACL strategii, která vám umožní spravovat oprávnění mezi skupinami uživatelů.",
|
|
44
77
|
"plugin.description.short": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT",
|
|
45
|
-
"plugin.name": "Role a oprávnění"
|
|
78
|
+
"plugin.name": "Role a oprávnění",
|
|
79
|
+
"popUpWarning.button.cancel": "Zrušit",
|
|
80
|
+
"popUpWarning.button.confirm": "Potvrdit",
|
|
81
|
+
"popUpWarning.title": "Prosím potvrďte",
|
|
82
|
+
"popUpWarning.warning.cancel": "Opravdu chcete zrušit své úpravy?"
|
|
46
83
|
}
|
|
@@ -14,37 +14,74 @@ var cs = {
|
|
|
14
14
|
"EditForm.inputToggle.label.email-confirmation-redirection": "Adresa pro přesměrování",
|
|
15
15
|
"EditForm.inputToggle.label.email-reset-password": "Stránka pro obnovení hesla",
|
|
16
16
|
"EditForm.inputToggle.label.sign-up": "Povolit registrace",
|
|
17
|
+
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/email-confirmation-redirection",
|
|
18
|
+
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
|
|
19
|
+
"EditPage.form.roles": "Detaily role",
|
|
20
|
+
"Email.template.data.loaded": "E-mailové šablony byly načteny",
|
|
21
|
+
"Email.template.email_confirmation": "Potvrzení e-mailové adresy",
|
|
22
|
+
"Email.template.reset_password": "Obnovení hesla",
|
|
23
|
+
"Email.template.form.edit.label": "Upravit šablonu",
|
|
24
|
+
"Email.template.table.action.label": "akce",
|
|
25
|
+
"Email.template.table.icon.label": "ikona",
|
|
26
|
+
"Email.template.table.name.label": "název",
|
|
27
|
+
"Form.advancedSettings.data.loaded": "Data pokročilých nastavení byla načtena",
|
|
17
28
|
"HeaderNav.link.advancedSettings": "Pokročilá nastavení",
|
|
18
29
|
"HeaderNav.link.emailTemplates": "E-mailové šablony",
|
|
19
30
|
"HeaderNav.link.providers": "Poskytovatelé",
|
|
20
|
-
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro
|
|
31
|
+
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro plugin {name}.",
|
|
21
32
|
"Plugins.header.description": "Pouze akce spojené s adresou jsou vypsány níže.",
|
|
22
33
|
"Plugins.header.title": "Povolení",
|
|
23
|
-
"Policies.header.hint": "Vyberte akce aplikace, nebo akce
|
|
34
|
+
"Policies.header.hint": "Vyberte akce aplikace, nebo akce pluginu a klikněte na ikonku ozubeného kolečka pro zobrazení adresy s nimi spojenou.",
|
|
24
35
|
"Policies.header.title": "Pokročilá nastavení",
|
|
25
36
|
"PopUpForm.Email.email_templates.inputDescription": "Pokud si nejste jisti jak používat proměnné, {link}",
|
|
37
|
+
"PopUpForm.Email.link.documentation": "podívejte se do naší dokumentace.",
|
|
26
38
|
"PopUpForm.Email.options.from.email.label": "Odesilatelův e-mail",
|
|
27
39
|
"PopUpForm.Email.options.from.email.placeholder": "jannovak@gmail.com",
|
|
28
40
|
"PopUpForm.Email.options.from.name.label": "Jméno odesilatele",
|
|
29
41
|
"PopUpForm.Email.options.from.name.placeholder": "Jan Novák",
|
|
30
42
|
"PopUpForm.Email.options.message.label": "Zpráva",
|
|
31
43
|
"PopUpForm.Email.options.object.label": "Předmět",
|
|
44
|
+
"PopUpForm.Email.options.object.placeholder": "Potvrďte prosím svou e-mailovou adresu pro %APP_NAME%",
|
|
32
45
|
"PopUpForm.Email.options.response_email.label": "Response e-mail",
|
|
33
46
|
"PopUpForm.Email.options.response_email.placeholder": "jannovak@gmail.com",
|
|
34
|
-
"PopUpForm.Providers.enabled.description": "
|
|
47
|
+
"PopUpForm.Providers.enabled.description": "Pokud je zakázáno, uživatelé nebudou moci tohoto poskytovatele použít.",
|
|
35
48
|
"PopUpForm.Providers.enabled.label": "Povolit",
|
|
36
49
|
"PopUpForm.Providers.key.label": "Client ID",
|
|
37
50
|
"PopUpForm.Providers.key.placeholder": "TEXT",
|
|
38
51
|
"PopUpForm.Providers.redirectURL.front-end.label": "Adresa pro přesměrování na vaši front-end aplikaci",
|
|
52
|
+
"PopUpForm.Providers.redirectURL.label": "Adresa pro přesměrování, kterou je třeba přidat do konfigurace vaší aplikace {provider}",
|
|
39
53
|
"PopUpForm.Providers.secret.label": "Client Secret",
|
|
40
54
|
"PopUpForm.Providers.secret.placeholder": "TEXT",
|
|
41
55
|
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
|
|
42
56
|
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
|
|
43
57
|
"PopUpForm.header.edit.email-templates": "Upravit e-mailové šablony",
|
|
58
|
+
"PopUpForm.header.edit.providers": "Upravit poskytovatele",
|
|
59
|
+
"Providers.data.loaded": "Poskytovatelé byli načteni",
|
|
60
|
+
"Providers.status": "Stav",
|
|
61
|
+
"Roles.empty": "Zatím nemáte žádné role.",
|
|
62
|
+
"Roles.empty.search": "Hledání neodpovídají žádné role.",
|
|
63
|
+
"Settings.roles.deleted": "Role smazána",
|
|
64
|
+
"Settings.roles.edited": "Role upravena",
|
|
65
|
+
"Settings.section-label": "Plugin Users & Permissions",
|
|
66
|
+
"components.Input.error.validation.email": "Toto není platný e-mail",
|
|
67
|
+
"components.Input.error.validation.json": "Toto neodpovídá formátu JSON",
|
|
68
|
+
"components.Input.error.validation.max": "Hodnota je příliš vysoká.",
|
|
69
|
+
"components.Input.error.validation.maxLength": "Hodnota je příliš dlouhá.",
|
|
70
|
+
"components.Input.error.validation.min": "Hodnota je příliš nízká.",
|
|
71
|
+
"components.Input.error.validation.minLength": "Hodnota je příliš krátká.",
|
|
72
|
+
"components.Input.error.validation.minSupMax": "Nemůže být vyšší",
|
|
73
|
+
"components.Input.error.validation.regex": "Hodnota neodpovídá regulárnímu výrazu.",
|
|
74
|
+
"components.Input.error.validation.required": "Tato hodnota je povinná.",
|
|
75
|
+
"components.Input.error.validation.unique": "Tato hodnota už je použita.",
|
|
44
76
|
"notification.success.submit": "Nastavení bylo aktualizování",
|
|
45
|
-
"
|
|
77
|
+
"page.title": "Nastavení - Role",
|
|
78
|
+
"plugin.description.long": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT. Tento plugin obsahuje ACL strategii, která vám umožní spravovat oprávnění mezi skupinami uživatelů.",
|
|
46
79
|
"plugin.description.short": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT",
|
|
47
|
-
"plugin.name": "Role a oprávnění"
|
|
80
|
+
"plugin.name": "Role a oprávnění",
|
|
81
|
+
"popUpWarning.button.cancel": "Zrušit",
|
|
82
|
+
"popUpWarning.button.confirm": "Potvrdit",
|
|
83
|
+
"popUpWarning.title": "Prosím potvrďte",
|
|
84
|
+
"popUpWarning.warning.cancel": "Opravdu chcete zrušit své úpravy?"
|
|
48
85
|
};
|
|
49
86
|
|
|
50
87
|
module.exports = cs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cs.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cs.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -12,37 +12,74 @@ var cs = {
|
|
|
12
12
|
"EditForm.inputToggle.label.email-confirmation-redirection": "Adresa pro přesměrování",
|
|
13
13
|
"EditForm.inputToggle.label.email-reset-password": "Stránka pro obnovení hesla",
|
|
14
14
|
"EditForm.inputToggle.label.sign-up": "Povolit registrace",
|
|
15
|
+
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/email-confirmation-redirection",
|
|
16
|
+
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
|
|
17
|
+
"EditPage.form.roles": "Detaily role",
|
|
18
|
+
"Email.template.data.loaded": "E-mailové šablony byly načteny",
|
|
19
|
+
"Email.template.email_confirmation": "Potvrzení e-mailové adresy",
|
|
20
|
+
"Email.template.reset_password": "Obnovení hesla",
|
|
21
|
+
"Email.template.form.edit.label": "Upravit šablonu",
|
|
22
|
+
"Email.template.table.action.label": "akce",
|
|
23
|
+
"Email.template.table.icon.label": "ikona",
|
|
24
|
+
"Email.template.table.name.label": "název",
|
|
25
|
+
"Form.advancedSettings.data.loaded": "Data pokročilých nastavení byla načtena",
|
|
15
26
|
"HeaderNav.link.advancedSettings": "Pokročilá nastavení",
|
|
16
27
|
"HeaderNav.link.emailTemplates": "E-mailové šablony",
|
|
17
28
|
"HeaderNav.link.providers": "Poskytovatelé",
|
|
18
|
-
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro
|
|
29
|
+
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro plugin {name}.",
|
|
19
30
|
"Plugins.header.description": "Pouze akce spojené s adresou jsou vypsány níže.",
|
|
20
31
|
"Plugins.header.title": "Povolení",
|
|
21
|
-
"Policies.header.hint": "Vyberte akce aplikace, nebo akce
|
|
32
|
+
"Policies.header.hint": "Vyberte akce aplikace, nebo akce pluginu a klikněte na ikonku ozubeného kolečka pro zobrazení adresy s nimi spojenou.",
|
|
22
33
|
"Policies.header.title": "Pokročilá nastavení",
|
|
23
34
|
"PopUpForm.Email.email_templates.inputDescription": "Pokud si nejste jisti jak používat proměnné, {link}",
|
|
35
|
+
"PopUpForm.Email.link.documentation": "podívejte se do naší dokumentace.",
|
|
24
36
|
"PopUpForm.Email.options.from.email.label": "Odesilatelův e-mail",
|
|
25
37
|
"PopUpForm.Email.options.from.email.placeholder": "jannovak@gmail.com",
|
|
26
38
|
"PopUpForm.Email.options.from.name.label": "Jméno odesilatele",
|
|
27
39
|
"PopUpForm.Email.options.from.name.placeholder": "Jan Novák",
|
|
28
40
|
"PopUpForm.Email.options.message.label": "Zpráva",
|
|
29
41
|
"PopUpForm.Email.options.object.label": "Předmět",
|
|
42
|
+
"PopUpForm.Email.options.object.placeholder": "Potvrďte prosím svou e-mailovou adresu pro %APP_NAME%",
|
|
30
43
|
"PopUpForm.Email.options.response_email.label": "Response e-mail",
|
|
31
44
|
"PopUpForm.Email.options.response_email.placeholder": "jannovak@gmail.com",
|
|
32
|
-
"PopUpForm.Providers.enabled.description": "
|
|
45
|
+
"PopUpForm.Providers.enabled.description": "Pokud je zakázáno, uživatelé nebudou moci tohoto poskytovatele použít.",
|
|
33
46
|
"PopUpForm.Providers.enabled.label": "Povolit",
|
|
34
47
|
"PopUpForm.Providers.key.label": "Client ID",
|
|
35
48
|
"PopUpForm.Providers.key.placeholder": "TEXT",
|
|
36
49
|
"PopUpForm.Providers.redirectURL.front-end.label": "Adresa pro přesměrování na vaši front-end aplikaci",
|
|
50
|
+
"PopUpForm.Providers.redirectURL.label": "Adresa pro přesměrování, kterou je třeba přidat do konfigurace vaší aplikace {provider}",
|
|
37
51
|
"PopUpForm.Providers.secret.label": "Client Secret",
|
|
38
52
|
"PopUpForm.Providers.secret.placeholder": "TEXT",
|
|
39
53
|
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
|
|
40
54
|
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
|
|
41
55
|
"PopUpForm.header.edit.email-templates": "Upravit e-mailové šablony",
|
|
56
|
+
"PopUpForm.header.edit.providers": "Upravit poskytovatele",
|
|
57
|
+
"Providers.data.loaded": "Poskytovatelé byli načteni",
|
|
58
|
+
"Providers.status": "Stav",
|
|
59
|
+
"Roles.empty": "Zatím nemáte žádné role.",
|
|
60
|
+
"Roles.empty.search": "Hledání neodpovídají žádné role.",
|
|
61
|
+
"Settings.roles.deleted": "Role smazána",
|
|
62
|
+
"Settings.roles.edited": "Role upravena",
|
|
63
|
+
"Settings.section-label": "Plugin Users & Permissions",
|
|
64
|
+
"components.Input.error.validation.email": "Toto není platný e-mail",
|
|
65
|
+
"components.Input.error.validation.json": "Toto neodpovídá formátu JSON",
|
|
66
|
+
"components.Input.error.validation.max": "Hodnota je příliš vysoká.",
|
|
67
|
+
"components.Input.error.validation.maxLength": "Hodnota je příliš dlouhá.",
|
|
68
|
+
"components.Input.error.validation.min": "Hodnota je příliš nízká.",
|
|
69
|
+
"components.Input.error.validation.minLength": "Hodnota je příliš krátká.",
|
|
70
|
+
"components.Input.error.validation.minSupMax": "Nemůže být vyšší",
|
|
71
|
+
"components.Input.error.validation.regex": "Hodnota neodpovídá regulárnímu výrazu.",
|
|
72
|
+
"components.Input.error.validation.required": "Tato hodnota je povinná.",
|
|
73
|
+
"components.Input.error.validation.unique": "Tato hodnota už je použita.",
|
|
42
74
|
"notification.success.submit": "Nastavení bylo aktualizování",
|
|
43
|
-
"
|
|
75
|
+
"page.title": "Nastavení - Role",
|
|
76
|
+
"plugin.description.long": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT. Tento plugin obsahuje ACL strategii, která vám umožní spravovat oprávnění mezi skupinami uživatelů.",
|
|
44
77
|
"plugin.description.short": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT",
|
|
45
|
-
"plugin.name": "Role a oprávnění"
|
|
78
|
+
"plugin.name": "Role a oprávnění",
|
|
79
|
+
"popUpWarning.button.cancel": "Zrušit",
|
|
80
|
+
"popUpWarning.button.confirm": "Potvrdit",
|
|
81
|
+
"popUpWarning.title": "Prosím potvrďte",
|
|
82
|
+
"popUpWarning.warning.cancel": "Opravdu chcete zrušit své úpravy?"
|
|
46
83
|
};
|
|
47
84
|
|
|
48
85
|
export { cs as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cs.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cs.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rateLimit.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -1,20 +1,98 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var rateLimit = require('../_virtual/rateLimit.js');
|
|
3
4
|
var require$$1$1 = require('path');
|
|
4
5
|
var require$$1 = require('@strapi/utils');
|
|
5
6
|
var require$$0 = require('lodash/fp');
|
|
6
7
|
var require$$3 = require('koa2-ratelimit');
|
|
7
8
|
|
|
8
|
-
var rateLimit;
|
|
9
9
|
var hasRequiredRateLimit;
|
|
10
10
|
function requireRateLimit() {
|
|
11
|
-
if (hasRequiredRateLimit) return rateLimit;
|
|
11
|
+
if (hasRequiredRateLimit) return rateLimit.__module.exports;
|
|
12
12
|
hasRequiredRateLimit = 1;
|
|
13
13
|
const path = require$$1$1;
|
|
14
14
|
const utils = require$$1;
|
|
15
15
|
const { isString, has, toLower } = require$$0;
|
|
16
16
|
const { RateLimitError } = utils.errors;
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Routes where the rate-limit key MUST NOT include a user identifier
|
|
19
|
+
* derived from `ctx.request.body.email`.
|
|
20
|
+
*
|
|
21
|
+
* On these routes the request body either has no `email` field
|
|
22
|
+
* (e.g. /auth/local uses `identifier`, /auth/reset-password uses
|
|
23
|
+
* `code`, /auth/change-password uses `currentPassword`) or the
|
|
24
|
+
* field is not part of the route contract. Including the
|
|
25
|
+
* attacker-controlled `body.email` in the rate-limit key on these
|
|
26
|
+
* routes lets a caller obtain a fresh key on every request by
|
|
27
|
+
* varying that field, effectively bypassing per-IP throttling.
|
|
28
|
+
*
|
|
29
|
+
* Comparison uses endsWith so the check is stable under any router
|
|
30
|
+
* mount prefix (e.g. `/api/auth/local`).
|
|
31
|
+
*
|
|
32
|
+
* @see https://github.com/strapi/strapi/security/advisories/GHSA-7mqx-wwh4-f9fw
|
|
33
|
+
*
|
|
34
|
+
* When adding a new `rateLimit`-protected auth route whose body does not
|
|
35
|
+
* use `email` as the real identifier, add its path suffix here (or an
|
|
36
|
+
* equivalent `routeUsesEmailIdentifier` rule) so the key cannot be split
|
|
37
|
+
* with arbitrary `body.email` values.
|
|
38
|
+
*/ const ROUTES_WITHOUT_IDENTIFIER = [
|
|
39
|
+
'/auth/local',
|
|
40
|
+
'/auth/reset-password',
|
|
41
|
+
'/auth/change-password'
|
|
42
|
+
];
|
|
43
|
+
const isOAuthCallbackPath = (requestPath)=>requestPath.includes('/connect/');
|
|
44
|
+
const routeUsesEmailIdentifier = (requestPath)=>{
|
|
45
|
+
if (isOAuthCallbackPath(requestPath)) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return !ROUTES_WITHOUT_IDENTIFIER.some((route)=>requestPath.endsWith(route));
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Paths suitable for route matching and prefix keys: POSIX-normalized,
|
|
52
|
+
* lower-cased, trailing slashes removed so `/api/auth/local` and
|
|
53
|
+
* `/api/auth/local/` share one bucket.
|
|
54
|
+
*/ const normalizeRequestPathForRateLimit = (requestPath)=>{
|
|
55
|
+
const normalized = path.normalize(requestPath);
|
|
56
|
+
const lower = toLower(normalized);
|
|
57
|
+
return lower.replace(/\/+$/, '') || '/';
|
|
58
|
+
};
|
|
59
|
+
const getEmailIdentifierForKey = (body)=>{
|
|
60
|
+
if (!body || !isString(body.email) || body.email === '') {
|
|
61
|
+
return 'unknownIdentifier';
|
|
62
|
+
}
|
|
63
|
+
return toLower(body.email);
|
|
64
|
+
};
|
|
65
|
+
const buildPrefixKey = (ctx)=>{
|
|
66
|
+
let requestPath;
|
|
67
|
+
if (!isString(ctx.request.path)) {
|
|
68
|
+
requestPath = 'invalidPath';
|
|
69
|
+
} else {
|
|
70
|
+
requestPath = normalizeRequestPathForRateLimit(ctx.request.path);
|
|
71
|
+
if (requestPath === '.' || requestPath === '..') {
|
|
72
|
+
requestPath = 'invalidPath';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!routeUsesEmailIdentifier(requestPath)) {
|
|
76
|
+
return `noIdentifier:${requestPath}:${ctx.request.ip}`;
|
|
77
|
+
}
|
|
78
|
+
const userIdentifier = getEmailIdentifierForKey(ctx.request.body);
|
|
79
|
+
return `${userIdentifier}:${requestPath}:${ctx.request.ip}`;
|
|
80
|
+
};
|
|
81
|
+
const buildRateLimitLoadConfig = (ctx, rateLimitConfig, routeMiddlewareConfig)=>{
|
|
82
|
+
return {
|
|
83
|
+
interval: {
|
|
84
|
+
min: 5
|
|
85
|
+
},
|
|
86
|
+
max: 5,
|
|
87
|
+
...rateLimitConfig,
|
|
88
|
+
...routeMiddlewareConfig,
|
|
89
|
+
handler () {
|
|
90
|
+
throw new RateLimitError();
|
|
91
|
+
},
|
|
92
|
+
prefixKey: buildPrefixKey(ctx)
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
rateLimit.__module.exports = (config, { strapi })=>async (ctx, next)=>{
|
|
18
96
|
let rateLimitConfig = strapi.config.get('plugin::users-permissions.ratelimit');
|
|
19
97
|
if (!rateLimitConfig) {
|
|
20
98
|
rateLimitConfig = {
|
|
@@ -26,25 +104,16 @@ function requireRateLimit() {
|
|
|
26
104
|
}
|
|
27
105
|
if (rateLimitConfig.enabled === true) {
|
|
28
106
|
const rateLimit = require$$3.RateLimit;
|
|
29
|
-
const
|
|
30
|
-
const requestPath = isString(ctx.request.path) ? toLower(path.normalize(ctx.request.path)) : 'invalidPath';
|
|
31
|
-
const loadConfig = {
|
|
32
|
-
interval: {
|
|
33
|
-
min: 5
|
|
34
|
-
},
|
|
35
|
-
max: 5,
|
|
36
|
-
prefixKey: `${userIdentifier}:${requestPath}:${ctx.request.ip}`,
|
|
37
|
-
handler () {
|
|
38
|
-
throw new RateLimitError();
|
|
39
|
-
},
|
|
40
|
-
...rateLimitConfig,
|
|
41
|
-
...config
|
|
42
|
-
};
|
|
107
|
+
const loadConfig = buildRateLimitLoadConfig(ctx, rateLimitConfig, config);
|
|
43
108
|
return rateLimit.middleware(loadConfig)(ctx, next);
|
|
44
109
|
}
|
|
45
110
|
return next();
|
|
46
111
|
};
|
|
47
|
-
|
|
112
|
+
rateLimit.__module.exports.buildPrefixKey = buildPrefixKey;
|
|
113
|
+
rateLimit.__module.exports.ROUTES_WITHOUT_IDENTIFIER = ROUTES_WITHOUT_IDENTIFIER;
|
|
114
|
+
rateLimit.__module.exports.normalizeRequestPathForRateLimit = normalizeRequestPathForRateLimit;
|
|
115
|
+
rateLimit.__module.exports.buildRateLimitLoadConfig = buildRateLimitLoadConfig;
|
|
116
|
+
return rateLimit.__module.exports;
|
|
48
117
|
}
|
|
49
118
|
|
|
50
119
|
exports.__require = requireRateLimit;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimit.js","sources":["../../../server/middlewares/rateLimit.js"],"sourcesContent":["'use strict';\n\nconst path = require('path');\nconst utils = require('@strapi/utils');\nconst { isString, has, toLower } = require('lodash/fp');\n\nconst { RateLimitError } = utils.errors;\n\
|
|
1
|
+
{"version":3,"file":"rateLimit.js","sources":["../../../server/middlewares/rateLimit.js"],"sourcesContent":["'use strict';\n\nconst path = require('path');\nconst utils = require('@strapi/utils');\nconst { isString, has, toLower } = require('lodash/fp');\n\nconst { RateLimitError } = utils.errors;\n\n/**\n * Routes where the rate-limit key MUST NOT include a user identifier\n * derived from `ctx.request.body.email`.\n *\n * On these routes the request body either has no `email` field\n * (e.g. /auth/local uses `identifier`, /auth/reset-password uses\n * `code`, /auth/change-password uses `currentPassword`) or the\n * field is not part of the route contract. Including the\n * attacker-controlled `body.email` in the rate-limit key on these\n * routes lets a caller obtain a fresh key on every request by\n * varying that field, effectively bypassing per-IP throttling.\n *\n * Comparison uses endsWith so the check is stable under any router\n * mount prefix (e.g. `/api/auth/local`).\n *\n * @see https://github.com/strapi/strapi/security/advisories/GHSA-7mqx-wwh4-f9fw\n *\n * When adding a new `rateLimit`-protected auth route whose body does not\n * use `email` as the real identifier, add its path suffix here (or an\n * equivalent `routeUsesEmailIdentifier` rule) so the key cannot be split\n * with arbitrary `body.email` values.\n */\nconst ROUTES_WITHOUT_IDENTIFIER = ['/auth/local', '/auth/reset-password', '/auth/change-password'];\n\nconst isOAuthCallbackPath = (requestPath) => requestPath.includes('/connect/');\n\nconst routeUsesEmailIdentifier = (requestPath) => {\n if (isOAuthCallbackPath(requestPath)) {\n return false;\n }\n\n return !ROUTES_WITHOUT_IDENTIFIER.some((route) => requestPath.endsWith(route));\n};\n\n/**\n * Paths suitable for route matching and prefix keys: POSIX-normalized,\n * lower-cased, trailing slashes removed so `/api/auth/local` and\n * `/api/auth/local/` share one bucket.\n */\nconst normalizeRequestPathForRateLimit = (requestPath) => {\n const normalized = path.normalize(requestPath);\n const lower = toLower(normalized);\n return lower.replace(/\\/+$/, '') || '/';\n};\n\nconst getEmailIdentifierForKey = (body) => {\n if (!body || !isString(body.email) || body.email === '') {\n return 'unknownIdentifier';\n }\n\n return toLower(body.email);\n};\n\nconst buildPrefixKey = (ctx) => {\n let requestPath;\n if (!isString(ctx.request.path)) {\n requestPath = 'invalidPath';\n } else {\n requestPath = normalizeRequestPathForRateLimit(ctx.request.path);\n if (requestPath === '.' || requestPath === '..') {\n requestPath = 'invalidPath';\n }\n }\n\n if (!routeUsesEmailIdentifier(requestPath)) {\n return `noIdentifier:${requestPath}:${ctx.request.ip}`;\n }\n\n const userIdentifier = getEmailIdentifierForKey(ctx.request.body);\n return `${userIdentifier}:${requestPath}:${ctx.request.ip}`;\n};\n\nconst buildRateLimitLoadConfig = (ctx, rateLimitConfig, routeMiddlewareConfig) => {\n return {\n interval: { min: 5 },\n max: 5,\n ...rateLimitConfig,\n ...routeMiddlewareConfig,\n handler() {\n throw new RateLimitError();\n },\n prefixKey: buildPrefixKey(ctx),\n };\n};\n\nmodule.exports =\n (config, { strapi }) =>\n async (ctx, next) => {\n let rateLimitConfig = strapi.config.get('plugin::users-permissions.ratelimit');\n\n if (!rateLimitConfig) {\n rateLimitConfig = {\n enabled: true,\n };\n }\n\n if (!has('enabled', rateLimitConfig)) {\n rateLimitConfig.enabled = true;\n }\n\n if (rateLimitConfig.enabled === true) {\n const rateLimit = require('koa2-ratelimit').RateLimit;\n\n const loadConfig = buildRateLimitLoadConfig(ctx, rateLimitConfig, config);\n\n return rateLimit.middleware(loadConfig)(ctx, next);\n }\n\n return next();\n };\n\nmodule.exports.buildPrefixKey = buildPrefixKey;\nmodule.exports.ROUTES_WITHOUT_IDENTIFIER = ROUTES_WITHOUT_IDENTIFIER;\nmodule.exports.normalizeRequestPathForRateLimit = normalizeRequestPathForRateLimit;\nmodule.exports.buildRateLimitLoadConfig = buildRateLimitLoadConfig;\n"],"names":["path","require$$0","utils","require$$1","isString","has","toLower","require$$2","RateLimitError","errors","ROUTES_WITHOUT_IDENTIFIER","isOAuthCallbackPath","requestPath","includes","routeUsesEmailIdentifier","some","route","endsWith","normalizeRequestPathForRateLimit","normalized","normalize","lower","replace","getEmailIdentifierForKey","body","email","buildPrefixKey","ctx","request","ip","userIdentifier","buildRateLimitLoadConfig","rateLimitConfig","routeMiddlewareConfig","interval","min","max","handler","prefixKey","rateLimitModule","exports","config","strapi","next","get","enabled","rateLimit","require$$3","RateLimit","loadConfig","middleware"],"mappings":"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"}
|
|
@@ -1,18 +1,96 @@
|
|
|
1
|
+
import { __module as rateLimit } from '../_virtual/rateLimit.mjs';
|
|
1
2
|
import require$$1$1 from 'path';
|
|
2
3
|
import require$$1 from '@strapi/utils';
|
|
3
4
|
import require$$0 from 'lodash/fp';
|
|
4
5
|
import require$$3 from 'koa2-ratelimit';
|
|
5
6
|
|
|
6
|
-
var rateLimit;
|
|
7
7
|
var hasRequiredRateLimit;
|
|
8
8
|
function requireRateLimit() {
|
|
9
|
-
if (hasRequiredRateLimit) return rateLimit;
|
|
9
|
+
if (hasRequiredRateLimit) return rateLimit.exports;
|
|
10
10
|
hasRequiredRateLimit = 1;
|
|
11
11
|
const path = require$$1$1;
|
|
12
12
|
const utils = require$$1;
|
|
13
13
|
const { isString, has, toLower } = require$$0;
|
|
14
14
|
const { RateLimitError } = utils.errors;
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Routes where the rate-limit key MUST NOT include a user identifier
|
|
17
|
+
* derived from `ctx.request.body.email`.
|
|
18
|
+
*
|
|
19
|
+
* On these routes the request body either has no `email` field
|
|
20
|
+
* (e.g. /auth/local uses `identifier`, /auth/reset-password uses
|
|
21
|
+
* `code`, /auth/change-password uses `currentPassword`) or the
|
|
22
|
+
* field is not part of the route contract. Including the
|
|
23
|
+
* attacker-controlled `body.email` in the rate-limit key on these
|
|
24
|
+
* routes lets a caller obtain a fresh key on every request by
|
|
25
|
+
* varying that field, effectively bypassing per-IP throttling.
|
|
26
|
+
*
|
|
27
|
+
* Comparison uses endsWith so the check is stable under any router
|
|
28
|
+
* mount prefix (e.g. `/api/auth/local`).
|
|
29
|
+
*
|
|
30
|
+
* @see https://github.com/strapi/strapi/security/advisories/GHSA-7mqx-wwh4-f9fw
|
|
31
|
+
*
|
|
32
|
+
* When adding a new `rateLimit`-protected auth route whose body does not
|
|
33
|
+
* use `email` as the real identifier, add its path suffix here (or an
|
|
34
|
+
* equivalent `routeUsesEmailIdentifier` rule) so the key cannot be split
|
|
35
|
+
* with arbitrary `body.email` values.
|
|
36
|
+
*/ const ROUTES_WITHOUT_IDENTIFIER = [
|
|
37
|
+
'/auth/local',
|
|
38
|
+
'/auth/reset-password',
|
|
39
|
+
'/auth/change-password'
|
|
40
|
+
];
|
|
41
|
+
const isOAuthCallbackPath = (requestPath)=>requestPath.includes('/connect/');
|
|
42
|
+
const routeUsesEmailIdentifier = (requestPath)=>{
|
|
43
|
+
if (isOAuthCallbackPath(requestPath)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return !ROUTES_WITHOUT_IDENTIFIER.some((route)=>requestPath.endsWith(route));
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Paths suitable for route matching and prefix keys: POSIX-normalized,
|
|
50
|
+
* lower-cased, trailing slashes removed so `/api/auth/local` and
|
|
51
|
+
* `/api/auth/local/` share one bucket.
|
|
52
|
+
*/ const normalizeRequestPathForRateLimit = (requestPath)=>{
|
|
53
|
+
const normalized = path.normalize(requestPath);
|
|
54
|
+
const lower = toLower(normalized);
|
|
55
|
+
return lower.replace(/\/+$/, '') || '/';
|
|
56
|
+
};
|
|
57
|
+
const getEmailIdentifierForKey = (body)=>{
|
|
58
|
+
if (!body || !isString(body.email) || body.email === '') {
|
|
59
|
+
return 'unknownIdentifier';
|
|
60
|
+
}
|
|
61
|
+
return toLower(body.email);
|
|
62
|
+
};
|
|
63
|
+
const buildPrefixKey = (ctx)=>{
|
|
64
|
+
let requestPath;
|
|
65
|
+
if (!isString(ctx.request.path)) {
|
|
66
|
+
requestPath = 'invalidPath';
|
|
67
|
+
} else {
|
|
68
|
+
requestPath = normalizeRequestPathForRateLimit(ctx.request.path);
|
|
69
|
+
if (requestPath === '.' || requestPath === '..') {
|
|
70
|
+
requestPath = 'invalidPath';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!routeUsesEmailIdentifier(requestPath)) {
|
|
74
|
+
return `noIdentifier:${requestPath}:${ctx.request.ip}`;
|
|
75
|
+
}
|
|
76
|
+
const userIdentifier = getEmailIdentifierForKey(ctx.request.body);
|
|
77
|
+
return `${userIdentifier}:${requestPath}:${ctx.request.ip}`;
|
|
78
|
+
};
|
|
79
|
+
const buildRateLimitLoadConfig = (ctx, rateLimitConfig, routeMiddlewareConfig)=>{
|
|
80
|
+
return {
|
|
81
|
+
interval: {
|
|
82
|
+
min: 5
|
|
83
|
+
},
|
|
84
|
+
max: 5,
|
|
85
|
+
...rateLimitConfig,
|
|
86
|
+
...routeMiddlewareConfig,
|
|
87
|
+
handler () {
|
|
88
|
+
throw new RateLimitError();
|
|
89
|
+
},
|
|
90
|
+
prefixKey: buildPrefixKey(ctx)
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
rateLimit.exports = (config, { strapi })=>async (ctx, next)=>{
|
|
16
94
|
let rateLimitConfig = strapi.config.get('plugin::users-permissions.ratelimit');
|
|
17
95
|
if (!rateLimitConfig) {
|
|
18
96
|
rateLimitConfig = {
|
|
@@ -24,25 +102,16 @@ function requireRateLimit() {
|
|
|
24
102
|
}
|
|
25
103
|
if (rateLimitConfig.enabled === true) {
|
|
26
104
|
const rateLimit = require$$3.RateLimit;
|
|
27
|
-
const
|
|
28
|
-
const requestPath = isString(ctx.request.path) ? toLower(path.normalize(ctx.request.path)) : 'invalidPath';
|
|
29
|
-
const loadConfig = {
|
|
30
|
-
interval: {
|
|
31
|
-
min: 5
|
|
32
|
-
},
|
|
33
|
-
max: 5,
|
|
34
|
-
prefixKey: `${userIdentifier}:${requestPath}:${ctx.request.ip}`,
|
|
35
|
-
handler () {
|
|
36
|
-
throw new RateLimitError();
|
|
37
|
-
},
|
|
38
|
-
...rateLimitConfig,
|
|
39
|
-
...config
|
|
40
|
-
};
|
|
105
|
+
const loadConfig = buildRateLimitLoadConfig(ctx, rateLimitConfig, config);
|
|
41
106
|
return rateLimit.middleware(loadConfig)(ctx, next);
|
|
42
107
|
}
|
|
43
108
|
return next();
|
|
44
109
|
};
|
|
45
|
-
|
|
110
|
+
rateLimit.exports.buildPrefixKey = buildPrefixKey;
|
|
111
|
+
rateLimit.exports.ROUTES_WITHOUT_IDENTIFIER = ROUTES_WITHOUT_IDENTIFIER;
|
|
112
|
+
rateLimit.exports.normalizeRequestPathForRateLimit = normalizeRequestPathForRateLimit;
|
|
113
|
+
rateLimit.exports.buildRateLimitLoadConfig = buildRateLimitLoadConfig;
|
|
114
|
+
return rateLimit.exports;
|
|
46
115
|
}
|
|
47
116
|
|
|
48
117
|
export { requireRateLimit as __require };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimit.mjs","sources":["../../../server/middlewares/rateLimit.js"],"sourcesContent":["'use strict';\n\nconst path = require('path');\nconst utils = require('@strapi/utils');\nconst { isString, has, toLower } = require('lodash/fp');\n\nconst { RateLimitError } = utils.errors;\n\
|
|
1
|
+
{"version":3,"file":"rateLimit.mjs","sources":["../../../server/middlewares/rateLimit.js"],"sourcesContent":["'use strict';\n\nconst path = require('path');\nconst utils = require('@strapi/utils');\nconst { isString, has, toLower } = require('lodash/fp');\n\nconst { RateLimitError } = utils.errors;\n\n/**\n * Routes where the rate-limit key MUST NOT include a user identifier\n * derived from `ctx.request.body.email`.\n *\n * On these routes the request body either has no `email` field\n * (e.g. /auth/local uses `identifier`, /auth/reset-password uses\n * `code`, /auth/change-password uses `currentPassword`) or the\n * field is not part of the route contract. Including the\n * attacker-controlled `body.email` in the rate-limit key on these\n * routes lets a caller obtain a fresh key on every request by\n * varying that field, effectively bypassing per-IP throttling.\n *\n * Comparison uses endsWith so the check is stable under any router\n * mount prefix (e.g. `/api/auth/local`).\n *\n * @see https://github.com/strapi/strapi/security/advisories/GHSA-7mqx-wwh4-f9fw\n *\n * When adding a new `rateLimit`-protected auth route whose body does not\n * use `email` as the real identifier, add its path suffix here (or an\n * equivalent `routeUsesEmailIdentifier` rule) so the key cannot be split\n * with arbitrary `body.email` values.\n */\nconst ROUTES_WITHOUT_IDENTIFIER = ['/auth/local', '/auth/reset-password', '/auth/change-password'];\n\nconst isOAuthCallbackPath = (requestPath) => requestPath.includes('/connect/');\n\nconst routeUsesEmailIdentifier = (requestPath) => {\n if (isOAuthCallbackPath(requestPath)) {\n return false;\n }\n\n return !ROUTES_WITHOUT_IDENTIFIER.some((route) => requestPath.endsWith(route));\n};\n\n/**\n * Paths suitable for route matching and prefix keys: POSIX-normalized,\n * lower-cased, trailing slashes removed so `/api/auth/local` and\n * `/api/auth/local/` share one bucket.\n */\nconst normalizeRequestPathForRateLimit = (requestPath) => {\n const normalized = path.normalize(requestPath);\n const lower = toLower(normalized);\n return lower.replace(/\\/+$/, '') || '/';\n};\n\nconst getEmailIdentifierForKey = (body) => {\n if (!body || !isString(body.email) || body.email === '') {\n return 'unknownIdentifier';\n }\n\n return toLower(body.email);\n};\n\nconst buildPrefixKey = (ctx) => {\n let requestPath;\n if (!isString(ctx.request.path)) {\n requestPath = 'invalidPath';\n } else {\n requestPath = normalizeRequestPathForRateLimit(ctx.request.path);\n if (requestPath === '.' || requestPath === '..') {\n requestPath = 'invalidPath';\n }\n }\n\n if (!routeUsesEmailIdentifier(requestPath)) {\n return `noIdentifier:${requestPath}:${ctx.request.ip}`;\n }\n\n const userIdentifier = getEmailIdentifierForKey(ctx.request.body);\n return `${userIdentifier}:${requestPath}:${ctx.request.ip}`;\n};\n\nconst buildRateLimitLoadConfig = (ctx, rateLimitConfig, routeMiddlewareConfig) => {\n return {\n interval: { min: 5 },\n max: 5,\n ...rateLimitConfig,\n ...routeMiddlewareConfig,\n handler() {\n throw new RateLimitError();\n },\n prefixKey: buildPrefixKey(ctx),\n };\n};\n\nmodule.exports =\n (config, { strapi }) =>\n async (ctx, next) => {\n let rateLimitConfig = strapi.config.get('plugin::users-permissions.ratelimit');\n\n if (!rateLimitConfig) {\n rateLimitConfig = {\n enabled: true,\n };\n }\n\n if (!has('enabled', rateLimitConfig)) {\n rateLimitConfig.enabled = true;\n }\n\n if (rateLimitConfig.enabled === true) {\n const rateLimit = require('koa2-ratelimit').RateLimit;\n\n const loadConfig = buildRateLimitLoadConfig(ctx, rateLimitConfig, config);\n\n return rateLimit.middleware(loadConfig)(ctx, next);\n }\n\n return next();\n };\n\nmodule.exports.buildPrefixKey = buildPrefixKey;\nmodule.exports.ROUTES_WITHOUT_IDENTIFIER = ROUTES_WITHOUT_IDENTIFIER;\nmodule.exports.normalizeRequestPathForRateLimit = normalizeRequestPathForRateLimit;\nmodule.exports.buildRateLimitLoadConfig = buildRateLimitLoadConfig;\n"],"names":["path","require$$0","utils","require$$1","isString","has","toLower","require$$2","RateLimitError","errors","ROUTES_WITHOUT_IDENTIFIER","isOAuthCallbackPath","requestPath","includes","routeUsesEmailIdentifier","some","route","endsWith","normalizeRequestPathForRateLimit","normalized","normalize","lower","replace","getEmailIdentifierForKey","body","email","buildPrefixKey","ctx","request","ip","userIdentifier","buildRateLimitLoadConfig","rateLimitConfig","routeMiddlewareConfig","interval","min","max","handler","prefixKey","rateLimitModule","exports","config","strapi","next","get","enabled","rateLimit","require$$3","RateLimit","loadConfig","middleware"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sources":["../../../../server/routes/content-api/auth.js"],"sourcesContent":["'use strict';\n\nconst { UsersPermissionsRouteValidator } = require('./validation');\n\nmodule.exports = (strapi) => {\n const validator = new UsersPermissionsRouteValidator(strapi);\n\n return [\n {\n method: 'GET',\n path: '/connect/(.*)',\n handler: 'auth.connect',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/local',\n handler: 'auth.callback',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.loginBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/local/register',\n handler: 'auth.register',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.registerBodySchema },\n },\n response: validator.authRegisterResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/:provider/callback',\n handler: 'auth.callback',\n config: {\n prefix: '',\n },\n request: {\n params: {\n provider: validator.providerParam,\n },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/forgot-password',\n handler: 'auth.forgotPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.forgotPasswordBodySchema },\n },\n response: validator.forgotPasswordResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/reset-password',\n handler: 'auth.resetPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.resetPasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/email-confirmation',\n handler: 'auth.emailConfirmation',\n config: {\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/send-email-confirmation',\n handler: 'auth.sendEmailConfirmation',\n config: {\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.sendEmailConfirmationBodySchema },\n },\n response: validator.sendEmailConfirmationResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/change-password',\n handler: 'auth.changePassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.changePasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/refresh',\n handler: 'auth.refresh',\n config: { prefix: '' },\n },\n {\n method: 'POST',\n path: '/auth/logout',\n handler: 'auth.logout',\n config: { prefix: '' },\n },\n ];\n};\n"],"names":["UsersPermissionsRouteValidator","require$$0","auth","strapi","validator","method","path","handler","config","middlewares","prefix","request","body","loginBodySchema","response","authResponseSchema","registerBodySchema","authRegisterResponseSchema","params","provider","providerParam","forgotPasswordBodySchema","forgotPasswordResponseSchema","resetPasswordBodySchema","sendEmailConfirmationBodySchema","sendEmailConfirmationResponseSchema","changePasswordBodySchema"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"auth.js","sources":["../../../../server/routes/content-api/auth.js"],"sourcesContent":["'use strict';\n\nconst { UsersPermissionsRouteValidator } = require('./validation');\n\nmodule.exports = (strapi) => {\n const validator = new UsersPermissionsRouteValidator(strapi);\n\n return [\n {\n method: 'GET',\n path: '/connect/(.*)',\n handler: 'auth.connect',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/local',\n handler: 'auth.callback',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.loginBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/local/register',\n handler: 'auth.register',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.registerBodySchema },\n },\n response: validator.authRegisterResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/:provider/callback',\n handler: 'auth.callback',\n config: {\n prefix: '',\n },\n request: {\n params: {\n provider: validator.providerParam,\n },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/forgot-password',\n handler: 'auth.forgotPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.forgotPasswordBodySchema },\n },\n response: validator.forgotPasswordResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/reset-password',\n handler: 'auth.resetPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.resetPasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/email-confirmation',\n handler: 'auth.emailConfirmation',\n config: {\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/send-email-confirmation',\n handler: 'auth.sendEmailConfirmation',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.sendEmailConfirmationBodySchema },\n },\n response: validator.sendEmailConfirmationResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/change-password',\n handler: 'auth.changePassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.changePasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/refresh',\n handler: 'auth.refresh',\n config: { prefix: '' },\n },\n {\n method: 'POST',\n path: '/auth/logout',\n handler: 'auth.logout',\n config: { prefix: '' },\n },\n ];\n};\n"],"names":["UsersPermissionsRouteValidator","require$$0","auth","strapi","validator","method","path","handler","config","middlewares","prefix","request","body","loginBodySchema","response","authResponseSchema","registerBodySchema","authRegisterResponseSchema","params","provider","providerParam","forgotPasswordBodySchema","forgotPasswordResponseSchema","resetPasswordBodySchema","sendEmailConfirmationBodySchema","sendEmailConfirmationResponseSchema","changePasswordBodySchema"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.mjs","sources":["../../../../server/routes/content-api/auth.js"],"sourcesContent":["'use strict';\n\nconst { UsersPermissionsRouteValidator } = require('./validation');\n\nmodule.exports = (strapi) => {\n const validator = new UsersPermissionsRouteValidator(strapi);\n\n return [\n {\n method: 'GET',\n path: '/connect/(.*)',\n handler: 'auth.connect',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/local',\n handler: 'auth.callback',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.loginBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/local/register',\n handler: 'auth.register',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.registerBodySchema },\n },\n response: validator.authRegisterResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/:provider/callback',\n handler: 'auth.callback',\n config: {\n prefix: '',\n },\n request: {\n params: {\n provider: validator.providerParam,\n },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/forgot-password',\n handler: 'auth.forgotPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.forgotPasswordBodySchema },\n },\n response: validator.forgotPasswordResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/reset-password',\n handler: 'auth.resetPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.resetPasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/email-confirmation',\n handler: 'auth.emailConfirmation',\n config: {\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/send-email-confirmation',\n handler: 'auth.sendEmailConfirmation',\n config: {\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.sendEmailConfirmationBodySchema },\n },\n response: validator.sendEmailConfirmationResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/change-password',\n handler: 'auth.changePassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.changePasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/refresh',\n handler: 'auth.refresh',\n config: { prefix: '' },\n },\n {\n method: 'POST',\n path: '/auth/logout',\n handler: 'auth.logout',\n config: { prefix: '' },\n },\n ];\n};\n"],"names":["UsersPermissionsRouteValidator","require$$0","auth","strapi","validator","method","path","handler","config","middlewares","prefix","request","body","loginBodySchema","response","authResponseSchema","registerBodySchema","authRegisterResponseSchema","params","provider","providerParam","forgotPasswordBodySchema","forgotPasswordResponseSchema","resetPasswordBodySchema","sendEmailConfirmationBodySchema","sendEmailConfirmationResponseSchema","changePasswordBodySchema"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"auth.mjs","sources":["../../../../server/routes/content-api/auth.js"],"sourcesContent":["'use strict';\n\nconst { UsersPermissionsRouteValidator } = require('./validation');\n\nmodule.exports = (strapi) => {\n const validator = new UsersPermissionsRouteValidator(strapi);\n\n return [\n {\n method: 'GET',\n path: '/connect/(.*)',\n handler: 'auth.connect',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/local',\n handler: 'auth.callback',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.loginBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/local/register',\n handler: 'auth.register',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.registerBodySchema },\n },\n response: validator.authRegisterResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/:provider/callback',\n handler: 'auth.callback',\n config: {\n prefix: '',\n },\n request: {\n params: {\n provider: validator.providerParam,\n },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/forgot-password',\n handler: 'auth.forgotPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.forgotPasswordBodySchema },\n },\n response: validator.forgotPasswordResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/reset-password',\n handler: 'auth.resetPassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.resetPasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'GET',\n path: '/auth/email-confirmation',\n handler: 'auth.emailConfirmation',\n config: {\n prefix: '',\n },\n },\n {\n method: 'POST',\n path: '/auth/send-email-confirmation',\n handler: 'auth.sendEmailConfirmation',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.sendEmailConfirmationBodySchema },\n },\n response: validator.sendEmailConfirmationResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/change-password',\n handler: 'auth.changePassword',\n config: {\n middlewares: ['plugin::users-permissions.rateLimit'],\n prefix: '',\n },\n request: {\n body: { 'application/json': validator.changePasswordBodySchema },\n },\n response: validator.authResponseSchema,\n },\n {\n method: 'POST',\n path: '/auth/refresh',\n handler: 'auth.refresh',\n config: { prefix: '' },\n },\n {\n method: 'POST',\n path: '/auth/logout',\n handler: 'auth.logout',\n config: { prefix: '' },\n },\n ];\n};\n"],"names":["UsersPermissionsRouteValidator","require$$0","auth","strapi","validator","method","path","handler","config","middlewares","prefix","request","body","loginBodySchema","response","authResponseSchema","registerBodySchema","authRegisterResponseSchema","params","provider","providerParam","forgotPasswordBodySchema","forgotPasswordResponseSchema","resetPasswordBodySchema","sendEmailConfirmationBodySchema","sendEmailConfirmationResponseSchema","changePasswordBodySchema"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/plugin-users-permissions",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.45.0",
|
|
4
4
|
"description": "Protect your API with a full-authentication process based on JWT",
|
|
5
5
|
"homepage": "https://strapi.io",
|
|
6
6
|
"bugs": {
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@strapi/design-system": "2.2.0",
|
|
57
57
|
"@strapi/icons": "2.2.0",
|
|
58
|
-
"@strapi/utils": "5.
|
|
58
|
+
"@strapi/utils": "5.45.0",
|
|
59
59
|
"bcryptjs": "2.4.3",
|
|
60
60
|
"formik": "2.4.5",
|
|
61
|
-
"grant": "
|
|
61
|
+
"grant": "5.4.24",
|
|
62
62
|
"immer": "9.0.21",
|
|
63
63
|
"jsonwebtoken": "9.0.0",
|
|
64
64
|
"jwk-to-pem": "2.0.7",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"zod": "3.25.67"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@strapi/strapi": "5.
|
|
78
|
+
"@strapi/strapi": "5.45.0",
|
|
79
79
|
"@testing-library/dom": "10.4.1",
|
|
80
80
|
"@testing-library/react": "16.3.0",
|
|
81
81
|
"@testing-library/user-event": "14.6.1",
|
|
@@ -6,6 +6,91 @@ const { isString, has, toLower } = require('lodash/fp');
|
|
|
6
6
|
|
|
7
7
|
const { RateLimitError } = utils.errors;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Routes where the rate-limit key MUST NOT include a user identifier
|
|
11
|
+
* derived from `ctx.request.body.email`.
|
|
12
|
+
*
|
|
13
|
+
* On these routes the request body either has no `email` field
|
|
14
|
+
* (e.g. /auth/local uses `identifier`, /auth/reset-password uses
|
|
15
|
+
* `code`, /auth/change-password uses `currentPassword`) or the
|
|
16
|
+
* field is not part of the route contract. Including the
|
|
17
|
+
* attacker-controlled `body.email` in the rate-limit key on these
|
|
18
|
+
* routes lets a caller obtain a fresh key on every request by
|
|
19
|
+
* varying that field, effectively bypassing per-IP throttling.
|
|
20
|
+
*
|
|
21
|
+
* Comparison uses endsWith so the check is stable under any router
|
|
22
|
+
* mount prefix (e.g. `/api/auth/local`).
|
|
23
|
+
*
|
|
24
|
+
* @see https://github.com/strapi/strapi/security/advisories/GHSA-7mqx-wwh4-f9fw
|
|
25
|
+
*
|
|
26
|
+
* When adding a new `rateLimit`-protected auth route whose body does not
|
|
27
|
+
* use `email` as the real identifier, add its path suffix here (or an
|
|
28
|
+
* equivalent `routeUsesEmailIdentifier` rule) so the key cannot be split
|
|
29
|
+
* with arbitrary `body.email` values.
|
|
30
|
+
*/
|
|
31
|
+
const ROUTES_WITHOUT_IDENTIFIER = ['/auth/local', '/auth/reset-password', '/auth/change-password'];
|
|
32
|
+
|
|
33
|
+
const isOAuthCallbackPath = (requestPath) => requestPath.includes('/connect/');
|
|
34
|
+
|
|
35
|
+
const routeUsesEmailIdentifier = (requestPath) => {
|
|
36
|
+
if (isOAuthCallbackPath(requestPath)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return !ROUTES_WITHOUT_IDENTIFIER.some((route) => requestPath.endsWith(route));
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Paths suitable for route matching and prefix keys: POSIX-normalized,
|
|
45
|
+
* lower-cased, trailing slashes removed so `/api/auth/local` and
|
|
46
|
+
* `/api/auth/local/` share one bucket.
|
|
47
|
+
*/
|
|
48
|
+
const normalizeRequestPathForRateLimit = (requestPath) => {
|
|
49
|
+
const normalized = path.normalize(requestPath);
|
|
50
|
+
const lower = toLower(normalized);
|
|
51
|
+
return lower.replace(/\/+$/, '') || '/';
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const getEmailIdentifierForKey = (body) => {
|
|
55
|
+
if (!body || !isString(body.email) || body.email === '') {
|
|
56
|
+
return 'unknownIdentifier';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return toLower(body.email);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const buildPrefixKey = (ctx) => {
|
|
63
|
+
let requestPath;
|
|
64
|
+
if (!isString(ctx.request.path)) {
|
|
65
|
+
requestPath = 'invalidPath';
|
|
66
|
+
} else {
|
|
67
|
+
requestPath = normalizeRequestPathForRateLimit(ctx.request.path);
|
|
68
|
+
if (requestPath === '.' || requestPath === '..') {
|
|
69
|
+
requestPath = 'invalidPath';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!routeUsesEmailIdentifier(requestPath)) {
|
|
74
|
+
return `noIdentifier:${requestPath}:${ctx.request.ip}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const userIdentifier = getEmailIdentifierForKey(ctx.request.body);
|
|
78
|
+
return `${userIdentifier}:${requestPath}:${ctx.request.ip}`;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const buildRateLimitLoadConfig = (ctx, rateLimitConfig, routeMiddlewareConfig) => {
|
|
82
|
+
return {
|
|
83
|
+
interval: { min: 5 },
|
|
84
|
+
max: 5,
|
|
85
|
+
...rateLimitConfig,
|
|
86
|
+
...routeMiddlewareConfig,
|
|
87
|
+
handler() {
|
|
88
|
+
throw new RateLimitError();
|
|
89
|
+
},
|
|
90
|
+
prefixKey: buildPrefixKey(ctx),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
9
94
|
module.exports =
|
|
10
95
|
(config, { strapi }) =>
|
|
11
96
|
async (ctx, next) => {
|
|
@@ -24,24 +109,15 @@ module.exports =
|
|
|
24
109
|
if (rateLimitConfig.enabled === true) {
|
|
25
110
|
const rateLimit = require('koa2-ratelimit').RateLimit;
|
|
26
111
|
|
|
27
|
-
const
|
|
28
|
-
const requestPath = isString(ctx.request.path)
|
|
29
|
-
? toLower(path.normalize(ctx.request.path))
|
|
30
|
-
: 'invalidPath';
|
|
31
|
-
|
|
32
|
-
const loadConfig = {
|
|
33
|
-
interval: { min: 5 },
|
|
34
|
-
max: 5,
|
|
35
|
-
prefixKey: `${userIdentifier}:${requestPath}:${ctx.request.ip}`,
|
|
36
|
-
handler() {
|
|
37
|
-
throw new RateLimitError();
|
|
38
|
-
},
|
|
39
|
-
...rateLimitConfig,
|
|
40
|
-
...config,
|
|
41
|
-
};
|
|
112
|
+
const loadConfig = buildRateLimitLoadConfig(ctx, rateLimitConfig, config);
|
|
42
113
|
|
|
43
114
|
return rateLimit.middleware(loadConfig)(ctx, next);
|
|
44
115
|
}
|
|
45
116
|
|
|
46
117
|
return next();
|
|
47
118
|
};
|
|
119
|
+
|
|
120
|
+
module.exports.buildPrefixKey = buildPrefixKey;
|
|
121
|
+
module.exports.ROUTES_WITHOUT_IDENTIFIER = ROUTES_WITHOUT_IDENTIFIER;
|
|
122
|
+
module.exports.normalizeRequestPathForRateLimit = normalizeRequestPathForRateLimit;
|
|
123
|
+
module.exports.buildRateLimitLoadConfig = buildRateLimitLoadConfig;
|