From ba057e791123ac302df3bd12c299f20c94ab57f7 Mon Sep 17 00:00:00 2001
From: Dicken
Date: Fri, 24 Jul 2026 16:16:10 +0200
Subject: [PATCH] round32: Bestaetigen-Button fuer Scan-Ergebnisse, API-Scan
auf wirklich nutzbare Endpunkte eingegrenzt, Firefox-Android-Hinweis mit
Alternativen
---
README.md | 8 ++++
apps/backend/src/scanner/apiDetector.ts | 21 +++------
.../frontend/src/routes/admin/ScannerPage.tsx | 43 ++++++++++++++++---
.../src/routes/admin/SettingsPage.tsx | 8 ++++
4 files changed, 61 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index fc9cfc2..cfa282b 100644
--- a/README.md
+++ b/README.md
@@ -298,6 +298,14 @@ Danach: `lp ` in die Adresszeile, Enter – landet bei eindeutigem
Treffer direkt beim Dienst, sonst auf der LaunchPad-Startseite mit bereits
eingetragenem Suchbegriff.
+**Android:** Firefox für Android unterstützt Schlagwort-Suchen (auch keine
+synchronisierten Desktop-Kürzel) grundsätzlich nicht – eine bekannte
+Firefox-Einschränkung, kein LaunchPad-Problem. Auf Android funktioniert die
+Chrome-Anleitung oben unverändert. Alternative für jeden Browser: die
+LaunchPad-Seite über „Zum Startbildschirm hinzufügen" als App-Symbol
+ablegen (LaunchPad ist als PWA installierbar) – ein Fingertipp genügt dann
+bis zum Suchfeld.
+
## Deployment auf unterschiedlichen Geräten
Läuft überall, wo Docker Compose verfügbar ist. Ein paar konkrete Wege:
diff --git a/apps/backend/src/scanner/apiDetector.ts b/apps/backend/src/scanner/apiDetector.ts
index d1dee9e..41b1ae7 100644
--- a/apps/backend/src/scanner/apiDetector.ts
+++ b/apps/backend/src/scanner/apiDetector.ts
@@ -62,7 +62,11 @@ function fetchRaw(url: string, timeoutMs = 2500): Promise
* Hinweis-Scanner, kein Sicherheits-/Pentesting-Werkzeug.
*/
const CANDIDATE_PATHS: { path: string; type: string }[] = [
- // Generische REST-/OpenAPI-/GraphQL-Konventionen
+ // Generische REST-/OpenAPI-/GraphQL-Konventionen - bewusst nur Pfade, die
+ // auf eine tatsächlich NUTZBARE/dokumentierte API hindeuten. Reine
+ // Status-/Health-/Metrik-Endpunkte (/health, /metrics, /actuator, ...)
+ // wurden bewusst rausgenommen: die bestätigen nur "hier läuft Software",
+ // sind aber keine API, mit der man tatsächlich etwas anfangen kann.
{ path: "/openapi.json", type: "OpenAPI" },
{ path: "/openapi.yaml", type: "OpenAPI" },
{ path: "/swagger.json", type: "OpenAPI (Swagger)" },
@@ -72,7 +76,6 @@ const CANDIDATE_PATHS: { path: string; type: string }[] = [
{ path: "/swagger/index.html", type: "Swagger-UI" },
{ path: "/swagger-ui", type: "Swagger-UI" },
{ path: "/redoc", type: "OpenAPI (ReDoc)" },
- { path: "/docs", type: "API-Dokumentation" },
{ path: "/graphql", type: "GraphQL" },
{ path: "/graphiql", type: "GraphQL" },
{ path: "/api/graphql", type: "GraphQL" },
@@ -84,17 +87,8 @@ const CANDIDATE_PATHS: { path: string; type: string }[] = [
{ path: "/rest", type: "REST-API" },
{ path: "/rpc", type: "JSON-RPC" },
{ path: "/jsonrpc", type: "JSON-RPC" },
- { path: "/api/status", type: "REST-API" },
- { path: "/api/system", type: "REST-API" },
- { path: "/api/info", type: "REST-API" },
- { path: "/api/version", type: "REST-API" },
- { path: "/api/config", type: "REST-API" },
- { path: "/actuator", type: "Spring-Boot-Actuator" },
- { path: "/actuator/health", type: "Spring-Boot-Actuator" },
- { path: "/metrics", type: "Metriken (Prometheus-Format)" },
- { path: "/healthz", type: "Health-Endpunkt" },
- { path: "/health", type: "Health-Endpunkt" },
- // Konkrete, in Homelabs verbreitete Software
+ // Konkrete, in Homelabs verbreitete Software - jeweils ein Endpunkt IHRER
+ // eigenen echten API (nicht nur ein Status-Ping), deshalb behalten.
{ path: "/api/config/core", type: "Home Assistant API" }, // erfordert Auth, meldet sich aber als API
{ path: "/api2/json/version", type: "Proxmox API" },
{ path: "/api/status", type: "Portainer API" },
@@ -102,7 +96,6 @@ const CANDIDATE_PATHS: { path: string; type: string }[] = [
{ path: "/admin/api.php", type: "Pi-hole API" },
{ path: "/System/Info/Public", type: "Jellyfin API" },
{ path: "/identity", type: "Plex API" },
- { path: "/api/health", type: "Grafana API" },
{ path: "/api/self", type: "Unifi-Controller API" },
{ path: "/api/v2/server/about", type: "Nextcloud API" },
{ path: "/ocs/v1.php/cloud/capabilities", type: "Nextcloud API" },
diff --git a/apps/frontend/src/routes/admin/ScannerPage.tsx b/apps/frontend/src/routes/admin/ScannerPage.tsx
index 9da6601..6f3fdd7 100644
--- a/apps/frontend/src/routes/admin/ScannerPage.tsx
+++ b/apps/frontend/src/routes/admin/ScannerPage.tsx
@@ -129,7 +129,13 @@ function NameChangesReview({
);
}
-function NewServicesList({ newServices }: { newServices: Service[] }) {
+function NewServicesList({
+ newServices,
+ onResolve,
+}: {
+ newServices: Service[];
+ onResolve: (id: string) => void;
+}) {
if (newServices.length === 0) return null;
return (
@@ -139,8 +145,19 @@ function NewServicesList({ newServices }: { newServices: Service[] }) {
{newServices.map((s) => (
-
- {s.displayName} ({s.hostname}:{s.port})
+
+
+ {s.displayName} ({s.hostname}:{s.port})
+
+ onResolve(s.id)}
+ title="Bestätigen (aus dieser Liste entfernen)"
+ aria-label="Bestätigen"
+ >
+
+
))}
@@ -375,7 +392,20 @@ function ApiScannerCard() {
{lastNewFindings.map(({ serviceId, serviceName, apis: entries }) => (
- {serviceName}
+
+
{serviceName}
+
+ setLastNewFindings((prev) => prev.filter((f) => f.serviceId !== serviceId))
+ }
+ title="Bestätigen (aus dieser Liste entfernen)"
+ aria-label="Bestätigen"
+ >
+
+
+
{entries.map((e) => (
@@ -626,7 +656,10 @@ export function ScannerPage() {
{bulkStatus ? (
{bulkStatus}
) : null}
-
+ setBulkNewServices((prev) => prev.filter((s) => s.id !== id))}
+ />
setBulkNameChanges((prev) => prev.filter((c) => nameChangeKey(c) !== key))}
diff --git a/apps/frontend/src/routes/admin/SettingsPage.tsx b/apps/frontend/src/routes/admin/SettingsPage.tsx
index f2dffa7..0c9f42b 100644
--- a/apps/frontend/src/routes/admin/SettingsPage.tsx
+++ b/apps/frontend/src/routes/admin/SettingsPage.tsx
@@ -374,6 +374,14 @@ function SearchEngineHint() {
Danach: „lp <suchbegriff>" in die Adresszeile – bei eindeutigem Treffer geht's direkt
zum Dienst, sonst zur LaunchPad-Suche mit vorbefülltem Begriff.
+
+ Android: Firefox für Android unterstützt Schlagwort-Suchen bislang
+ grundsätzlich nicht (auch keine synchronisierten Desktop-Kürzel) – das ist eine
+ Firefox-Einschränkung, kein LaunchPad-Problem. Auf Android funktioniert es in{" "}
+ Chrome genauso wie oben für Chrome/Edge beschrieben. Alternative: die
+ LaunchPad-Seite über „Zum Startbildschirm hinzufügen" als App-Symbol ablegen – dann reicht
+ ein Fingertipp bis zum Suchfeld.
+
) : null}