Configure hotspot credentials from dashboard

This commit is contained in:
2026-07-31 20:41:16 +02:00
parent e52d2690ee
commit d1239d66af
19 changed files with 443 additions and 23 deletions
+46 -1
View File
@@ -19,7 +19,13 @@ import {
} from "./security.js";
import { collectSystemStatus } from "./status.js";
import { readUpdateStatus, triggerSystemUpdate } from "./update.js";
import { networkActionSchema, readNetworkStatus, requestNetworkAction } from "./network.js";
import {
hotspotConfigurationSchema,
networkActionSchema,
readNetworkStatus,
requestHotspotConfiguration,
requestNetworkAction
} from "./network.js";
import { collectAdbStatus } from "./adb.js";
import "./types.js";
@@ -319,6 +325,45 @@ export async function buildApp(config: AppConfig): Promise<FastifyInstance> {
return readNetworkStatus(config);
});
app.post(
"/api/network/configuration",
{ config: { rateLimit: { max: 3, timeWindow: "10 minutes" } } },
async (request, reply) => {
if (!requireUser(request, reply)) return;
const parsed = hotspotConfigurationSchema.safeParse(request.body);
if (!parsed.success) {
return reply.code(400).send({
error: {
code: "INVALID_HOTSPOT_CONFIGURATION",
message: parsed.error.issues[0]?.message ?? "The hotspot settings are invalid"
}
});
}
try {
const configuration = await requestHotspotConfiguration(config, parsed.data, request.authUser!.id);
audit(database, {
actorUserId: request.authUser!.id,
action: "network.configure-hotspot",
result: "success",
ipAddress: clientAddress(request),
details: { requestId: configuration.id }
});
return reply.code(202).send({ accepted: true, requestId: configuration.id });
} catch {
audit(database, {
actorUserId: request.authUser!.id,
action: "network.configure-hotspot",
result: "failure",
ipAddress: clientAddress(request),
details: { reason: "configuration_service_unavailable" }
});
return reply.code(503).send({
error: { code: "HOTSPOT_CONFIGURATION_UNAVAILABLE", message: "The hotspot configuration service is unavailable" }
});
}
}
);
app.post("/api/network/actions", async (request, reply) => {
if (!requireUser(request, reply)) return;
const parsed = z.object({ action: networkActionSchema }).safeParse(request.body);