generated from Dicken/dickendock
Commit 5: Scanner-Engine (DNS, Portscan, Titel/Favicon, Softwareerkennung, FritzBox TR-064)
This commit is contained in:
94
apps/backend/src/routes/scan.ts
Normal file
94
apps/backend/src/routes/scan.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import * as deviceRepo from "../db/repositories/devices.js";
|
||||
import * as serviceRepo from "../db/repositories/services.js";
|
||||
import { scanDeviceServices } from "../scanner/networkScanner.js";
|
||||
import { fetchFritzBoxHosts } from "../scanner/fritzbox.js";
|
||||
|
||||
/**
|
||||
* Scan-Endpunkte. Werden ausschließlich manuell per Knopfdruck ("Jetzt
|
||||
* scannen") aus der Admin-UI (Commit 6) ausgelöst – es gibt keinerlei
|
||||
* automatischen/zeitgesteuerten Scan.
|
||||
*/
|
||||
export async function scanRoutes(app: FastifyInstance): Promise<void> {
|
||||
// Netzwerk-Scan für ein einzelnes, bereits bekanntes Gerät: DNS-Kandidaten,
|
||||
// Port 80/443 + typische Ports, Titel/Favicon, Softwareerkennung.
|
||||
app.post("/api/scan/devices/:id", async (request, reply) => {
|
||||
const { id } = request.params as { id: string };
|
||||
const device = deviceRepo.getDevice(id);
|
||||
if (!device) {
|
||||
return reply.code(404).send({ error: "Gerät nicht gefunden" });
|
||||
}
|
||||
|
||||
const discovered = await scanDeviceServices(device);
|
||||
|
||||
const results = discovered.map((found) =>
|
||||
serviceRepo.upsertServiceFromScan({
|
||||
deviceId: device.id,
|
||||
hostname: found.hostname,
|
||||
url: found.url,
|
||||
https: found.https,
|
||||
port: found.port,
|
||||
favicon: found.favicon,
|
||||
description: found.description,
|
||||
suggestedDisplayName: found.suggestedDisplayName,
|
||||
suggestedCategory: found.category,
|
||||
})
|
||||
);
|
||||
|
||||
deviceRepo.upsertDeviceFromScan({
|
||||
hostname: device.hostname,
|
||||
ip: device.ip,
|
||||
mac: device.mac,
|
||||
manufacturer: device.manufacturer,
|
||||
model: device.model,
|
||||
online: discovered.length > 0,
|
||||
source: device.source,
|
||||
});
|
||||
|
||||
return {
|
||||
deviceId: device.id,
|
||||
scannedPorts: discovered.length,
|
||||
created: results.filter((r) => r.created).length,
|
||||
updated: results.filter((r) => !r.created).length,
|
||||
services: results.map((r) => r.service),
|
||||
};
|
||||
});
|
||||
|
||||
// FritzBox-Scan: liest die Geräteliste per TR-064 und legt/aktualisiert Geräte.
|
||||
// Erfordert FRITZBOX_HOST / FRITZBOX_USERNAME / FRITZBOX_PASSWORD (optional
|
||||
// FRITZBOX_PORT, Default 49000) als Umgebungsvariablen.
|
||||
app.post("/api/scan/fritzbox", async (request, reply) => {
|
||||
const host = process.env.FRITZBOX_HOST;
|
||||
const username = process.env.FRITZBOX_USERNAME;
|
||||
const password = process.env.FRITZBOX_PASSWORD;
|
||||
|
||||
if (!host || !username || !password) {
|
||||
return reply.code(400).send({
|
||||
error:
|
||||
"FritzBox nicht konfiguriert. Bitte FRITZBOX_HOST, FRITZBOX_USERNAME und FRITZBOX_PASSWORD setzen.",
|
||||
});
|
||||
}
|
||||
|
||||
const port = process.env.FRITZBOX_PORT ? Number(process.env.FRITZBOX_PORT) : 49000;
|
||||
|
||||
try {
|
||||
const hosts = await fetchFritzBoxHosts({ host, port, username, password });
|
||||
const devices = hosts.map((h) =>
|
||||
deviceRepo.upsertDeviceFromScan({
|
||||
hostname: h.hostname,
|
||||
ip: h.ip,
|
||||
mac: h.mac,
|
||||
online: h.online,
|
||||
source: "fritzbox",
|
||||
})
|
||||
);
|
||||
return { found: hosts.length, devices };
|
||||
} catch (err) {
|
||||
request.log.error(err);
|
||||
return reply.code(502).send({
|
||||
error: "FritzBox-Scan fehlgeschlagen",
|
||||
detail: err instanceof Error ? err.message : String(err),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user