Commit 8: Plugin-System (Scanner erweitern, Geräte importieren, Icons)

This commit is contained in:
2026-07-19 10:14:43 +02:00
parent 6a7eb3dfe5
commit 986de50963
20 changed files with 517 additions and 20 deletions

View File

@@ -0,0 +1,78 @@
# LaunchPad-Plugins
Jeder Unterordner hier ist ein Plugin. Erkannt wird alles, was eine
`index.js` mit einem passenden Default-Export enthält kein Rebuild des
Docker-Images nötig, dieser Ordner wird zur Laufzeit als Volume eingebunden
(siehe `docker-compose.yml`). Nach dem Hinzufügen/Ändern eines Plugins
reicht ein Neustart des Backend-Containers:
```bash
docker compose restart backend
```
## Minimalstruktur
```
apps/backend/plugins/mein-plugin/
└── index.js
```
```js
export default {
name: "mein-plugin",
version: "1.0.0",
description: "Kurze Beschreibung, erscheint unter Admin -> Plugins",
// optional: Scanner erweitern
setup(ctx) {
ctx.registerSoftwareSignature({
name: "Meine Software",
category: "Sonstiges",
icon: "🔧", // Emoji oder Icon-URL
matches: (input) => !!input.body && /meine-software/i.test(input.body),
});
},
// optional: eigene Geräte-Importquelle
async importDevices() {
return [
{ hostname: "beispiel", ip: "192.168.1.99", source: "plugin" },
];
},
};
```
Beide Funktionen (`setup`, `importDevices`) sind optional ein Plugin kann
nur die eine, nur die andere, oder beide implementieren. Reines JavaScript
(ESM), kein Build-Schritt nötig.
## Was Plugins aktuell können
- **Scanner registrieren**: `ctx.registerSoftwareSignature(...)` in `setup()`
fügt der automatischen Softwareerkennung (siehe `apps/backend/src/scanner/softwareDetection.ts`)
eine zusätzliche Signatur hinzu, inklusive eigenem Icon. Wird bei jedem
Geräte-Scan berücksichtigt.
- **Geräte importieren**: `importDevices()` liefert eine Liste von Geräten,
die per Knopfdruck unter Admin -> Plugins importiert werden
(`POST /api/plugins/:name/import`). Abgeglichen wird wie bei Scans über
MAC/IP ein erneuter Import überschreibt keine Gerätefelder, die der
Nutzer zwischenzeitlich geändert hat, außer den scan-eigenen (siehe
`upsertDeviceFromScan`).
- **Icons bereitstellen**: über `icon` an einer registrierten Signatur. Wird
als Startwert für neu angelegte Dienste übernommen (wie `category`
niemals nachträglich überschrieben, siehe README Hauptprojekt).
## Was (noch) nicht geht
- Eigene Admin-Menüpunkte/Unterseiten (aktuell erscheinen alle Plugins
gesammelt auf einer Seite unter Admin -> Plugins, keine eigene Route pro
Plugin).
- Kein Sandboxing: Plugin-Code läuft mit vollem Zugriff im Backend-Prozess.
Nur Plugins aus vertrauenswürdiger Quelle einbinden.
## Beispiel-Plugins
- `example-signatures/` registriert zwei zusätzliche Software-Signaturen
(Homebridge, Uptime Kuma).
- `static-import/` importiert Geräte aus einer lokalen `devices.json`
(standardmäßig leer, siehe `devices.example.json` für das Format).

View File

@@ -0,0 +1,29 @@
/**
* Beispiel-Plugin: registriert zwei zusätzliche Softwareerkennungen, die
* nicht in der eingebauten Liste enthalten sind, inklusive eigenem Icon.
*
* Zeigt das setup()-Pattern: ein Plugin bekommt beim Laden einen Kontext mit
* registerSoftwareSignature() und kann darüber den Scanner erweitern.
*/
export default {
name: "example-signatures",
version: "1.0.0",
description:
"Erkennt Homebridge und Uptime Kuma zusätzlich zu den eingebauten Signaturen.",
setup(ctx) {
ctx.registerSoftwareSignature({
name: "Homebridge",
category: "Smart Home",
icon: "🏠",
matches: (input) => !!input.body && /homebridge/i.test(input.body),
});
ctx.registerSoftwareSignature({
name: "Uptime Kuma",
category: "Monitoring",
icon: "📈",
matches: (input) => !!input.body && /uptime\s*kuma/i.test(input.body),
});
},
};

View File

@@ -0,0 +1,9 @@
[
{
"hostname": "nas",
"ip": "192.168.1.20",
"mac": "AA:BB:CC:DD:EE:FF",
"manufacturer": "Synology",
"model": "DS920+"
}
]

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,40 @@
import { readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const currentDir = dirname(fileURLToPath(import.meta.url));
/**
* Beispiel-Plugin: importiert Geräte aus einer lokalen devices.json neben
* diesem Plugin. Zeigt das importDevices()-Pattern für eigene Datenquellen
* (z. B. ein Inventar-Export oder eine externe API) im Unterschied zu den
* Netzwerk-Scannern rein datengetrieben, kein eigener Netzwerkzugriff nötig.
*
* Standardmäßig ist devices.json leer, damit beim ersten Start keine
* Fantasiegeräte auftauchen. Zum Ausprobieren einfach Einträge ergänzen und
* unter Admin -> Plugins auf "Jetzt importieren" klicken.
*/
export default {
name: "static-import",
version: "1.0.0",
description: "Importiert Geräte aus plugins/static-import/devices.json.",
async importDevices() {
try {
const raw = readFileSync(join(currentDir, "devices.json"), "utf-8");
const entries = JSON.parse(raw);
return entries.map((entry) => ({
hostname: entry.hostname,
ip: entry.ip,
mac: entry.mac ?? undefined,
manufacturer: entry.manufacturer ?? undefined,
model: entry.model ?? undefined,
online: false,
source: "plugin",
}));
} catch {
return [];
}
},
};