diff --git a/Core/API/SettingsAPI.class.php b/Core/API/SettingsAPI.class.php index 9f332aa..e6d2867 100644 --- a/Core/API/SettingsAPI.class.php +++ b/Core/API/SettingsAPI.class.php @@ -21,7 +21,7 @@ namespace Core\API { "allowed_extensions" => new ArrayType("allowed_extensions", Parameter::TYPE_STRING), "trusted_domains" => new ArrayType("trusted_domains", Parameter::TYPE_STRING), "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, "disabled", CaptchaProvider::PROVIDERS), "mail_enabled" => new Parameter("mail_enabled", Parameter::TYPE_BOOLEAN), "mail_port" => new IntegerType("mail_port", 1, 65535), "rate_limiting_enabled" => new Parameter("rate_limiting_enabled", Parameter::TYPE_BOOLEAN), diff --git a/Core/API/Stats.class.php b/Core/API/Stats.class.php index d93567f..5048863 100644 --- a/Core/API/Stats.class.php +++ b/Core/API/Stats.class.php @@ -46,11 +46,12 @@ class Stats extends Request { "server" => [ "version" => WEBBASE_VERSION, "server" => $_SERVER["SERVER_SOFTWARE"] ?? "Unknown", - "memory_usage" => memory_get_usage(), - "load_avg" => $loadAvg, + "memoryUsage" => memory_get_usage(), + "loadAverage" => $loadAvg, "database" => $this->context->getSQL()->getStatus(), "mail" => $settings->isMailEnabled(), - "captcha" => $settings->getCaptchaProvider()?->jsonSerialize() + "captcha" => $settings->getCaptchaProvider()?->jsonSerialize(), + "rateLimiting" => $settings->isRateLimitingEnabled() ], ]; diff --git a/Core/API/UserAPI.class.php b/Core/API/UserAPI.class.php index 266d0a6..17def1d 100644 --- a/Core/API/UserAPI.class.php +++ b/Core/API/UserAPI.class.php @@ -1470,6 +1470,10 @@ namespace Core\API\User { 'token' => new StringType('token', 36), )); $this->userToken = null; + $this->rateLimiting = new RateLimiting( + new RateLimitRule(10, 30, RateLimitRule::SECOND), + new RateLimitRule(30, 1, RateLimitRule::MINUTE), + ); } public function getToken(): ?UserToken { diff --git a/Core/Configuration/Settings.class.php b/Core/Configuration/Settings.class.php index e0b7337..9f62a90 100644 --- a/Core/Configuration/Settings.class.php +++ b/Core/Configuration/Settings.class.php @@ -109,7 +109,7 @@ class Settings { $settings->timeZone = date_default_timezone_get(); // captcha - $settings->captchaProvider = "none"; + $settings->captchaProvider = "disabled"; $settings->captchaSiteKey = ""; $settings->captchaSecretKey = ""; diff --git a/Core/Localization/de_DE/settings.php b/Core/Localization/de_DE/settings.php index 8a30217..4c3c14a 100644 --- a/Core/Localization/de_DE/settings.php +++ b/Core/Localization/de_DE/settings.php @@ -3,6 +3,8 @@ return [ "title" => "Einstellungen", "information" => "Informationen", + "disabled" => "Deaktiviert", + "enabled" => "Aktiviert", # API Key "api_key" => "API Schlüssel", @@ -44,6 +46,8 @@ return [ "captcha_provider" => "Captcha Anbieter", "captcha_site_key" => "Öffentlicher Captcha Schlüssel", "captcha_secret_key" => "Geheimer Captcha Schlüssel", + "recaptcha" => "Google reCaptcha", + "hcaptcha" => "hCaptcha", # redis "rate_limit" => "Rate-Limit", diff --git a/Core/Localization/en_US/settings.php b/Core/Localization/en_US/settings.php index e794333..06a42b4 100644 --- a/Core/Localization/en_US/settings.php +++ b/Core/Localization/en_US/settings.php @@ -3,6 +3,8 @@ return [ "title" => "Settings", "information" => "Information", + "disabled" => "Disabled", + "enabled" => "Enabled", # API Key "api_key" => "API Key", @@ -44,6 +46,8 @@ return [ "captcha_provider" => "Captcha Provider", "captcha_site_key" => "Captcha Site Key", "captcha_secret_key" => "Secret Captcha Key", + "recaptcha" => "Google reCaptcha", + "hcaptcha" => "hCaptcha", # redis "rate_limit" => "Rate Limiting", diff --git a/Core/Objects/Captcha/CaptchaProvider.class.php b/Core/Objects/Captcha/CaptchaProvider.class.php index 49be622..67af00d 100644 --- a/Core/Objects/Captcha/CaptchaProvider.class.php +++ b/Core/Objects/Captcha/CaptchaProvider.class.php @@ -6,11 +6,11 @@ use Core\Objects\ApiObject; abstract class CaptchaProvider extends ApiObject { - const NONE = "none"; + const DISABLED = "disabled"; const RECAPTCHA = "recaptcha"; const HCAPTCHA = "hcaptcha"; - const PROVIDERS = [self::NONE, self::RECAPTCHA, self::HCAPTCHA]; + const PROVIDERS = [self::DISABLED, self::RECAPTCHA, self::HCAPTCHA]; private string $siteKey; private string $secretKey; diff --git a/react/admin-panel/src/views/overview.js b/react/admin-panel/src/views/overview.js index 934104c..c4b51af 100644 --- a/react/admin-panel/src/views/overview.js +++ b/react/admin-panel/src/views/overview.js @@ -2,8 +2,18 @@ import * as React from "react"; import {Link} from "react-router-dom"; import {useCallback, useContext, useEffect, useState} from "react"; import {LocaleContext} from "shared/locale"; -import {ArrowCircleRight, BugReport, Groups, LibraryBooks, People} from "@mui/icons-material"; -import {CircularProgress} from "@mui/material"; +import {humanReadableSize} from "shared/util"; +import {sprintf} from "sprintf-js"; +import { + ArrowCircleRight, + BugReport, + CheckCircle, + Groups, + HighlightOff, + LibraryBooks, + People +} from "@mui/icons-material"; +import {Box, CircularProgress, Paper, Table, TableBody, TableCell, TableRow} from "@mui/material"; const StatBox = (props) =>
@@ -24,6 +34,19 @@ const StatBox = (props) =>
+const StatusLine = (props) => { + const {enabled, text, ...other} = props; + if (enabled) { + return + {text} + + } else { + return + {text} + + } +} + export default function Overview(props) { const [fetchStats, setFetchStats] = useState(true); @@ -32,7 +55,7 @@ export default function Overview(props) { useEffect(() => { - requestModules(props.api, ["general", "admin"], currentLocale).then(data => { + requestModules(props.api, ["general", "admin", "settings"], currentLocale).then(data => { if (!data.success) { props.showDialog("Error fetching translations: " + data.msg); } @@ -56,12 +79,10 @@ export default function Overview(props) { onFetchStats(); }, []); - /* - let loadAvg = this.state.server.load_avg; - if (Array.isArray(this.state.server.load_avg)) { - loadAvg = this.state.server.load_avg.join(" "); + let loadAvg = stats ? stats.server.loadAverage : null; + if (Array.isArray(loadAvg)) { + loadAvg = loadAvg.map(v => sprintf("%.1f", v)).join(", "); } - */ return <>
@@ -100,6 +121,59 @@ export default function Overview(props) { link={"/admin/logs"} />
+ +

Server Stats


+ {stats === null ? : + + + + Web-Base Version + {stats.server.version} + + + Server + {stats.server.server ?? "Unknown"} + + + Load Average + {loadAvg} + + + Memory Usage + {humanReadableSize(stats.server.memoryUsage)} + + + Database + {stats.server.database} + + + Captcha + + + + + + Mail + + + + + + Rate-Limiting + + + + + +
+ } +
} diff --git a/react/admin-panel/src/views/settings/settings.js b/react/admin-panel/src/views/settings/settings.js index baabe92..4bc68fa 100644 --- a/react/admin-panel/src/views/settings/settings.js +++ b/react/admin-panel/src/views/settings/settings.js @@ -283,10 +283,16 @@ export default function SettingsView(props) { ]; } else if (selectedTab === "captcha") { + let captchaOptions = {}; + ["disabled", "recaptcha", "hcaptcha"].reduce((map, key) => { + map[key] = L("settings." + key); + return map; + }, captchaOptions); + return [ - renderSelection("captcha_provider", {"none": L("settings.none"), "recaptcha": "Google reCaptcha", "hcaptcha": "hCaptcha"}), - renderTextInput("captcha_site_key", settings.captcha_provider === "none"), - renderPasswordInput("captcha_secret_key", settings.captcha_provider === "none"), + renderSelection("captcha_provider", captchaOptions), + renderTextInput("captcha_site_key", settings.captcha_provider === "disabled"), + renderPasswordInput("captcha_secret_key", settings.captcha_provider === "disabled"), ]; } else if (selectedTab === "redis") { return [