generated from Dicken/dickendock
89 lines
3.5 KiB
TypeScript
89 lines
3.5 KiB
TypeScript
export interface SoftwareSignatureInput {
|
|
server?: string;
|
|
body?: string;
|
|
title?: string;
|
|
port: number;
|
|
}
|
|
|
|
export interface SoftwareSignature {
|
|
name: string;
|
|
category: string;
|
|
matches: (input: SoftwareSignatureInput) => boolean;
|
|
/** Optional: Emoji oder Icon-URL, von Plugins bereitgestellt (siehe apps/backend/plugins). */
|
|
icon?: string;
|
|
}
|
|
|
|
function bodyContains(input: SoftwareSignatureInput, pattern: RegExp): boolean {
|
|
return !!input.body && pattern.test(input.body);
|
|
}
|
|
|
|
function titleMatches(input: SoftwareSignatureInput, pattern: RegExp): boolean {
|
|
return !!input.title && pattern.test(input.title.trim());
|
|
}
|
|
|
|
/**
|
|
* Automatische Softwareerkennung anhand von HTTP-Response-Merkmalen
|
|
* (Server-Header, HTML-Inhalt). Liste gemäß Spezifikation.
|
|
*
|
|
* Grundsatz: der `<title>`-Tag ist ein viel präziseres Signal als der
|
|
* komplette Seiteninhalt und wird deshalb wo möglich zuerst geprüft. Reine
|
|
* Volltextsuche im Body (bodyContains) besonders bei Marken-/Produktnamen
|
|
* aus generischen Alltagswörtern (z. B. "Home Assistant") kann in
|
|
* minifiziertem JavaScript anderer Web-UIs zufällig zutreffen - siehe
|
|
* Bugreport: FritzBox-Repeater wurden fälschlich als "Home Assistant"
|
|
* erkannt, weil beide Wörter irgendwo im ausgelieferten JS vorkamen.
|
|
*/
|
|
export const SOFTWARE_SIGNATURES: SoftwareSignature[] = [
|
|
{
|
|
name: "Home Assistant",
|
|
category: "Smart Home",
|
|
matches: (i) =>
|
|
titleMatches(i, /^home\s*assistant$/i) || bodyContains(i, /frontend_latest\//i),
|
|
},
|
|
{
|
|
name: "Synology DSM",
|
|
category: "NAS",
|
|
matches: (i) => bodyContains(i, /synology/i) || (!!i.server && /synology/i.test(i.server)),
|
|
},
|
|
{ name: "Frigate", category: "Überwachung", matches: (i) => bodyContains(i, /frigate/i) },
|
|
{ name: "Portainer", category: "Container", matches: (i) => bodyContains(i, /portainer/i) },
|
|
{ name: "Grafana", category: "Monitoring", matches: (i) => bodyContains(i, /grafana/i) },
|
|
{ name: "Proxmox VE", category: "Virtualisierung", matches: (i) => bodyContains(i, /proxmox/i) },
|
|
{ name: "Immich", category: "Fotos", matches: (i) => bodyContains(i, /immich/i) },
|
|
{ name: "Paperless-ngx", category: "Dokumente", matches: (i) => bodyContains(i, /paperless/i) },
|
|
{ name: "Gitea", category: "Entwicklung", matches: (i) => bodyContains(i, /gitea/i) },
|
|
{
|
|
name: "Vaultwarden",
|
|
category: "Passwörter",
|
|
matches: (i) => bodyContains(i, /vaultwarden|bitwarden/i),
|
|
},
|
|
{ name: "Jellyfin", category: "Medien", matches: (i) => bodyContains(i, /jellyfin/i) },
|
|
{ name: "Nextcloud", category: "Cloud", matches: (i) => bodyContains(i, /nextcloud/i) },
|
|
{ name: "Pi-hole", category: "DNS", matches: (i) => bodyContains(i, /pi-?hole/i) },
|
|
{
|
|
name: "AdGuard Home",
|
|
category: "DNS",
|
|
matches: (i) => bodyContains(i, /adguard/i) || titleMatches(i, /adguard/i),
|
|
},
|
|
{ name: "UniFi Network", category: "Netzwerk", matches: (i) => bodyContains(i, /unifi/i) },
|
|
];
|
|
|
|
/**
|
|
* Zusätzliche Signaturen, die von Plugins zur Laufzeit registriert werden
|
|
* (siehe apps/backend/src/plugins/loader.ts). Eingebaute Signaturen haben
|
|
* Vorrang, falls beide zufällig auf denselben Dienst passen.
|
|
*/
|
|
const pluginSignatures: SoftwareSignature[] = [];
|
|
|
|
export function registerSoftwareSignature(signature: SoftwareSignature): void {
|
|
pluginSignatures.push(signature);
|
|
}
|
|
|
|
export function detectSoftware(input: SoftwareSignatureInput): SoftwareSignature | null {
|
|
return (
|
|
SOFTWARE_SIGNATURES.find((signature) => signature.matches(input)) ??
|
|
pluginSignatures.find((signature) => signature.matches(input)) ??
|
|
null
|
|
);
|
|
}
|