diff --git a/docs/widgets/services/crowdsec.md b/docs/widgets/services/crowdsec.md
new file mode 100644
index 000000000..da4d5e090
--- /dev/null
+++ b/docs/widgets/services/crowdsec.md
@@ -0,0 +1,17 @@
+---
+title: Crowdsec
+description: Crowdsec Widget Configuration
+---
+
+Learn more about [Crowdsec](https://crowdsec.net).
+
+Get your API key by registering a bouncer with your instance, see the [Crowdsec docs](https://docs.crowdsec.net/docs/local_api/intro#bouncers).
+
+Allowed fields: ["totalDecisions", "activeBans"]
+
+```yaml
+widget:
+ type: crowdsec
+ url: http://crowdsechostorip:port
+ key: yourcrowdsecbouncerkey
+```
diff --git a/mkdocs.yml b/mkdocs.yml
index a0994fadd..e58cb1e4e 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -44,6 +44,7 @@ nav:
- widgets/services/channelsdvrserver.md
- widgets/services/cloudflared.md
- widgets/services/coin-market-cap.md
+ - widgets/services/crowdsec.md
- widgets/services/customapi.md
- widgets/services/deluge.md
- widgets/services/diskstation.md
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index c7339c0b3..39cb3230d 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -872,5 +872,10 @@
"labels": "Labels",
"users": "Users",
"totalValue": "Total Value"
+ },
+ "crowdsec": {
+ "bans": "Bans",
+ "captchas": "Captchas",
+ "rateLimits": "Rate Limits"
}
}
diff --git a/src/widgets/components.js b/src/widgets/components.js
index f3d567bb7..8c85bd770 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -15,6 +15,7 @@ const components = {
channelsdvrserver: dynamic(() => import("./channelsdvrserver/component")),
cloudflared: dynamic(() => import("./cloudflared/component")),
coinmarketcap: dynamic(() => import("./coinmarketcap/component")),
+ crowdsec: dynamic(() => import("./crowdsec/component")),
iframe: dynamic(() => import("./iframe/component")),
customapi: dynamic(() => import("./customapi/component")),
deluge: dynamic(() => import("./deluge/component")),
diff --git a/src/widgets/crowdsec/component.jsx b/src/widgets/crowdsec/component.jsx
new file mode 100644
index 000000000..4e6c1babd
--- /dev/null
+++ b/src/widgets/crowdsec/component.jsx
@@ -0,0 +1,39 @@
+import { useTranslation } from "next-i18next";
+
+import Container from "components/services/widget/container";
+import Block from "components/services/widget/block";
+import useWidgetAPI from "utils/proxy/use-widget-api";
+
+export default function Component({ service }) {
+ const { t } = useTranslation();
+
+ const { widget } = service;
+
+ const { data: bansData, error: bansError } = useWidgetAPI(widget, "bans");
+ const { data: captchasData, error: captchasError } = useWidgetAPI(widget, "captchas");
+ const { data: rateLimitsData, error: rateLimitsError } = useWidgetAPI(widget, "rateLimits");
+
+ if (bansError || captchasError || rateLimitsError) {
+ return ;
+ }
+
+ if (!bansData && !captchasData && !rateLimitsData) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ console.log(bansData);
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/widgets/crowdsec/widget.js b/src/widgets/crowdsec/widget.js
new file mode 100644
index 000000000..80b510fbd
--- /dev/null
+++ b/src/widgets/crowdsec/widget.js
@@ -0,0 +1,20 @@
+import credentialedProxyHandler from "utils/proxy/handlers/credentialed";
+
+const widget = {
+ api: "{url}/v1/{endpoint}",
+ proxyHandler: credentialedProxyHandler,
+
+ mappings: {
+ bans: {
+ endpoint: "decisions?type=ban&origins=crowdsec",
+ },
+ captchas: {
+ endpoint: "decisions?type=captcha&origins=crowdsec",
+ },
+ rateLimits: {
+ endpoint: "decisions?type=rate-limit&origins=crowdsec",
+ },
+ },
+};
+
+export default widget;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index a9cae230f..6e02d9329 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -12,6 +12,7 @@ import changedetectionio from "./changedetectionio/widget";
import channelsdvrserver from "./channelsdvrserver/widget";
import cloudflared from "./cloudflared/widget";
import coinmarketcap from "./coinmarketcap/widget";
+import crowdsec from "./crowdsec/widget";
import customapi from "./customapi/widget";
import deluge from "./deluge/widget";
import diskstation from "./diskstation/widget";
@@ -125,6 +126,7 @@ const widgets = {
channelsdvrserver,
cloudflared,
coinmarketcap,
+ crowdsec,
customapi,
deluge,
diskstation,