Rate Limiting settings

This commit is contained in:
Roman 2024-04-23 20:35:58 +02:00
parent 6c39c292b0
commit fad1188ee8
6 changed files with 44 additions and 19 deletions

@ -30,7 +30,6 @@ namespace Core\API {
$password = $settings["mail_password"] ?? ""; $password = $settings["mail_password"] ?? "";
$connectionData = new ConnectionData($host, $port, $login, $password); $connectionData = new ConnectionData($host, $port, $login, $password);
$connectionData->setProperty("from", $settings["mail_from"] ?? ""); $connectionData->setProperty("from", $settings["mail_from"] ?? "");
$connectionData->setProperty("last_sync", $settings["mail_last_sync"] ?? "");
$connectionData->setProperty("mail_footer", $settings["mail_footer"] ?? ""); $connectionData->setProperty("mail_footer", $settings["mail_footer"] ?? "");
$connectionData->setProperty("mail_async", $settings["mail_async"] ?? false); $connectionData->setProperty("mail_async", $settings["mail_async"] ?? false);
return $connectionData; return $connectionData;

@ -16,7 +16,6 @@ namespace Core\API {
public function __construct(Context $context, bool $externalCall = false, array $params = array()) { public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
parent::__construct($context, $externalCall, $params); parent::__construct($context, $externalCall, $params);
// TODO: improve this, additional validation for allowed chars etc.
// API parameters should be more configurable, e.g. allow regexes, min/max values for numbers, etc. // API parameters should be more configurable, e.g. allow regexes, min/max values for numbers, etc.
$this->predefinedKeys = [ $this->predefinedKeys = [
"allowed_extensions" => new ArrayType("allowed_extensions", Parameter::TYPE_STRING), "allowed_extensions" => new ArrayType("allowed_extensions", Parameter::TYPE_STRING),
@ -24,7 +23,9 @@ namespace Core\API {
"user_registration_enabled" => new Parameter("user_registration_enabled", Parameter::TYPE_BOOLEAN), "user_registration_enabled" => new Parameter("user_registration_enabled", Parameter::TYPE_BOOLEAN),
"captcha_provider" => new StringType("captcha_provider", -1, true, "none", CaptchaProvider::PROVIDERS), "captcha_provider" => new StringType("captcha_provider", -1, true, "none", CaptchaProvider::PROVIDERS),
"mail_enabled" => new Parameter("mail_enabled", Parameter::TYPE_BOOLEAN), "mail_enabled" => new Parameter("mail_enabled", Parameter::TYPE_BOOLEAN),
"mail_port" => new IntegerType("mail_port", 1, 65535) "mail_port" => new IntegerType("mail_port", 1, 65535),
"rate_limiting_enabled" => new Parameter("rate_limiting_enabled", Parameter::TYPE_BOOLEAN),
"redis_port" => new IntegerType("redis_port", 1, 65535),
]; ];
} }
} }

@ -181,7 +181,6 @@ class Settings {
->addRow("mail_username", '""', false, false) ->addRow("mail_username", '""', false, false)
->addRow("mail_password", '""', true, false) ->addRow("mail_password", '""', true, false)
->addRow("mail_from", '""', false, false) ->addRow("mail_from", '""', false, false)
->addRow("mail_last_sync", '""', false, false)
->addRow("mail_footer", '""', false, false) ->addRow("mail_footer", '""', false, false)
->addRow("mail_async", false, false, false) ->addRow("mail_async", false, false, false)
->addRow("rate_limiting_enabled", json_encode($this->allowedExtensions), false, false) ->addRow("rate_limiting_enabled", json_encode($this->allowedExtensions), false, false)

@ -45,6 +45,13 @@ return [
"captcha_site_key" => "Öffentlicher Captcha Schlüssel", "captcha_site_key" => "Öffentlicher Captcha Schlüssel",
"captcha_secret_key" => "Geheimer Captcha Schlüssel", "captcha_secret_key" => "Geheimer Captcha Schlüssel",
# redis
"rate_limit" => "Rate-Limit",
"rate_limiting_enabled" => "Rate-Limiting aktiviert",
"redis_host" => "Redis Host",
"redis_port" => "Redis Port",
"redis_password" => "Redis Passwort",
# dialog # dialog
"fetch_settings_error" => "Fehler beim Holen der Einstellungen", "fetch_settings_error" => "Fehler beim Holen der Einstellungen",
"save_settings_success" => "Einstellungen erfolgreich gespeichert", "save_settings_success" => "Einstellungen erfolgreich gespeichert",

@ -45,6 +45,13 @@ return [
"captcha_site_key" => "Captcha Site Key", "captcha_site_key" => "Captcha Site Key",
"captcha_secret_key" => "Secret Captcha Key", "captcha_secret_key" => "Secret Captcha Key",
# redis
"rate_limit" => "Rate Limiting",
"rate_limiting_enabled" => "Rate Limiting enabled",
"redis_host" => "Redis host",
"redis_port" => "Redis port",
"redis_password" => "Redis password",
# dialog # dialog
"fetch_settings_error" => "Error fetching settings", "fetch_settings_error" => "Error fetching settings",
"save_settings_success" => "Settings saved successfully", "save_settings_success" => "Settings saved successfully",

@ -23,11 +23,10 @@ import {
RestartAlt, RestartAlt,
Save, Save,
Send, Send,
SettingsApplications, SmartToy SettingsApplications, SmartToy, Storage
} from "@mui/icons-material"; } from "@mui/icons-material";
import TIME_ZONES from "shared/time-zones"; import TIME_ZONES from "shared/time-zones";
import ButtonBar from "../../elements/button-bar"; import ButtonBar from "../../elements/button-bar";
import {parseBool} from "shared/util";
import SettingsTextValues from "./input-text-values"; import SettingsTextValues from "./input-text-values";
import SettingsCheckBox from "./input-check-box"; import SettingsCheckBox from "./input-check-box";
import SettingsNumberInput from "./input-number"; import SettingsNumberInput from "./input-number";
@ -67,7 +66,12 @@ export default function SettingsView(props) {
"captcha_secret_key", "captcha_secret_key",
"captcha_site_key", "captcha_site_key",
], ],
"hidden": ["installation_completed", "mail_last_sync"] "redis": [
"rate_limiting_enabled",
"redis_host",
"redis_port",
"redis_password"
]
}; };
// data // data
@ -105,7 +109,6 @@ export default function SettingsView(props) {
showDialog(data.msg, L("settings.fetch_settings_error")); showDialog(data.msg, L("settings.fetch_settings_error"));
} else { } else {
setSettings(Object.keys(data.settings) setSettings(Object.keys(data.settings)
.filter(key => !KNOWN_SETTING_KEYS.hidden.includes(key))
.reduce((obj, key) => { .reduce((obj, key) => {
obj[key] = data.settings[key]; obj[key] = data.settings[key];
return obj; return obj;
@ -248,27 +251,27 @@ export default function SettingsView(props) {
} else if (selectedTab === "mail") { } else if (selectedTab === "mail") {
return [ return [
renderCheckBox("mail_enabled"), renderCheckBox("mail_enabled"),
renderTextInput("mail_from", !parseBool(settings.mail_enabled)), renderTextInput("mail_from", !settings.mail_enabled),
renderTextInput("mail_host", !parseBool(settings.mail_enabled)), renderTextInput("mail_host", !settings.mail_enabled),
renderNumberInput("mail_port", 1, 65535, !parseBool(settings.mail_enabled)), renderNumberInput("mail_port", 1, 65535, !settings.mail_enabled),
renderTextInput("mail_username", !parseBool(settings.mail_enabled)), renderTextInput("mail_username", !settings.mail_enabled),
renderPasswordInput("mail_password", !parseBool(settings.mail_enabled)), renderPasswordInput("mail_password", !settings.mail_enabled),
renderTextInput("mail_footer", !parseBool(settings.mail_enabled)), renderTextInput("mail_footer", !settings.mail_enabled),
renderCheckBox("mail_async", !parseBool(settings.mail_enabled)), renderCheckBox("mail_async", !settings.mail_enabled),
<FormGroup key={"mail-test"}> <FormGroup key={"mail-test"}>
<FormLabel>{L("settings.send_test_email")}</FormLabel> <FormLabel>{L("settings.send_test_email")}</FormLabel>
<FormControl disabled={!parseBool(settings.mail_enabled)}> <FormControl disabled={!settings.mail_enabled}>
<Grid container spacing={1}> <Grid container spacing={1}>
<Grid item xs={1}> <Grid item xs={1}>
<Button startIcon={isSending ? <CircularProgress size={14} /> : <Send />} <Button startIcon={isSending ? <CircularProgress size={14} /> : <Send />}
variant={"outlined"} onClick={onSendTestMail} variant={"outlined"} onClick={onSendTestMail}
fullWidth={true} fullWidth={true}
disabled={!parseBool(settings.mail_enabled) || isSending || !api.hasPermission("mail/test")}> disabled={!settings.mail_enabled || isSending || !api.hasPermission("mail/test")}>
{isSending ? L("general.sending") + "…" : L("general.send")} {isSending ? L("general.sending") + "…" : L("general.send")}
</Button> </Button>
</Grid> </Grid>
<Grid item xs={11}> <Grid item xs={11}>
<TextField disabled={!parseBool(settings.mail_enabled)} <TextField disabled={!settings.mail_enabled}
fullWidth={true} fullWidth={true}
variant={"outlined"} value={testMailAddress} variant={"outlined"} value={testMailAddress}
onChange={e => setTestMailAddress(e.target.value)} onChange={e => setTestMailAddress(e.target.value)}
@ -285,6 +288,13 @@ export default function SettingsView(props) {
renderTextInput("captcha_site_key", settings.captcha_provider === "none"), renderTextInput("captcha_site_key", settings.captcha_provider === "none"),
renderPasswordInput("captcha_secret_key", settings.captcha_provider === "none"), renderPasswordInput("captcha_secret_key", settings.captcha_provider === "none"),
]; ];
} else if (selectedTab === "redis") {
return [
renderCheckBox("rate_limiting_enabled"),
renderTextInput("redis_host", !settings.rate_limiting_enabled),
renderNumberInput("redis_port", 1, 65535, !settings.rate_limiting_enabled),
renderPasswordInput("redis_password", !settings.rate_limiting_enabled),
];
} else if (selectedTab === "uncategorized") { } else if (selectedTab === "uncategorized") {
return <TableContainer component={Paper}> return <TableContainer component={Paper}>
<Table> <Table>
@ -365,6 +375,8 @@ export default function SettingsView(props) {
icon={<Mail />} iconPosition={"start"} /> icon={<Mail />} iconPosition={"start"} />
<Tab value={"captcha"} label={L("settings.captcha")} <Tab value={"captcha"} label={L("settings.captcha")}
icon={<SmartToy />} iconPosition={"start"} /> icon={<SmartToy />} iconPosition={"start"} />
<Tab value={"redis"} label={L("settings.rate_limit")}
icon={<Storage />} iconPosition={"start"} />
<Tab value={"uncategorized"} label={L("settings.uncategorized")} <Tab value={"uncategorized"} label={L("settings.uncategorized")}
icon={<LibraryBooks />} iconPosition={"start"} /> icon={<LibraryBooks />} iconPosition={"start"} />
</Tabs> </Tabs>