Configure hotspot credentials from dashboard
This commit is contained in:
@@ -20,7 +20,8 @@ function testConfig(): AppConfig {
|
||||
network: {
|
||||
enabled: false,
|
||||
statusPath: `/tmp/pi-car-companion-test-${process.pid}-missing-network-status.json`,
|
||||
commandPath: `/tmp/pi-car-companion-test-${process.pid}-network-command.json`
|
||||
commandPath: `/tmp/pi-car-companion-test-${process.pid}-network-command.json`,
|
||||
configurationRequestPath: `/tmp/pi-car-companion-test-${process.pid}-network-configuration.json`
|
||||
},
|
||||
adb: { enabled: false, executable: "adb", serial: null, timeoutMs: 3_000 }
|
||||
};
|
||||
@@ -210,6 +211,15 @@ describe("authentication boundary", () => {
|
||||
payload: { action: "retry-upstream" }
|
||||
});
|
||||
expect(action.statusCode).toBe(503);
|
||||
|
||||
const invalidConfiguration = await app.inject({
|
||||
method: "POST",
|
||||
url: "/api/network/configuration",
|
||||
headers: { ...mutationHeaders(token), cookie },
|
||||
payload: { ssid: "bad/name", password: "short" }
|
||||
});
|
||||
expect(invalidConfiguration.statusCode).toBe(400);
|
||||
expect(invalidConfiguration.json()).toMatchObject({ error: { code: "INVALID_HOTSPOT_CONFIGURATION" } });
|
||||
});
|
||||
|
||||
it("exposes only allowlisted jobs and authenticated run history", async () => {
|
||||
|
||||
@@ -26,7 +26,8 @@ describe("ADB configuration", () => {
|
||||
expect(loadConfig({ NODE_ENV: "test" }).network).toEqual({
|
||||
enabled: false,
|
||||
statusPath: "/var/lib/pi-car-companion/network-status.json",
|
||||
commandPath: "/var/lib/pi-car-companion/network-command.json"
|
||||
commandPath: "/var/lib/pi-car-companion/network-command.json",
|
||||
configurationRequestPath: "/var/lib/pi-car-companion/network-configuration-request.json"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,14 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import type { AppConfig } from "../src/config.js";
|
||||
import { consumeNetworkCommand, readNetworkStatus, requestNetworkAction } from "../src/network.js";
|
||||
import {
|
||||
consumeHotspotConfigurationRequest,
|
||||
consumeNetworkCommand,
|
||||
hotspotConfigurationSchema,
|
||||
readNetworkStatus,
|
||||
requestHotspotConfiguration,
|
||||
requestNetworkAction
|
||||
} from "../src/network.js";
|
||||
|
||||
const directories: string[] = [];
|
||||
|
||||
@@ -18,7 +25,12 @@ function config(directory: string, enabled = true): AppConfig {
|
||||
allowedOrigins: new Set(),
|
||||
updateStatusPath: join(directory, "update.json"),
|
||||
versionFile: join(directory, "REVISION"),
|
||||
network: { enabled, statusPath: join(directory, "status.json"), commandPath: join(directory, "command.json") },
|
||||
network: {
|
||||
enabled,
|
||||
statusPath: join(directory, "status.json"),
|
||||
commandPath: join(directory, "command.json"),
|
||||
configurationRequestPath: join(directory, "configuration.json")
|
||||
},
|
||||
adb: { enabled: false, executable: "adb", serial: null, timeoutMs: 3_000 }
|
||||
};
|
||||
}
|
||||
@@ -49,4 +61,21 @@ describe("network control boundary", () => {
|
||||
await writeFile(testConfig.network.statusPath, '{"mode":"shell"}');
|
||||
await expect(readNetworkStatus(testConfig)).resolves.toMatchObject({ supported: false, mode: "starting" });
|
||||
});
|
||||
|
||||
it("validates and transfers hotspot credentials only through the root request file", async () => {
|
||||
const directory = await mkdtemp(join(tmpdir(), "pi-car-network-test-"));
|
||||
directories.push(directory);
|
||||
const testConfig = config(directory, false);
|
||||
expect(hotspotConfigurationSchema.safeParse({ ssid: "MG4 Car", password: "Strong pass!2" }).success).toBe(true);
|
||||
expect(hotspotConfigurationSchema.safeParse({ ssid: "bad/name", password: "Strong pass!2" }).success).toBe(false);
|
||||
expect(hotspotConfigurationSchema.safeParse({ ssid: "MG4 Car", password: "short" }).success).toBe(false);
|
||||
|
||||
await requestHotspotConfiguration(testConfig, { ssid: "MG4 Car", password: "Strong pass!2" }, 7, async () => undefined);
|
||||
await expect(consumeHotspotConfigurationRequest(testConfig.network.configurationRequestPath)).resolves.toMatchObject({
|
||||
ssid: "MG4 Car",
|
||||
password: "Strong pass!2",
|
||||
actorUserId: 7
|
||||
});
|
||||
await expect(readFile(testConfig.network.configurationRequestPath, "utf8")).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,7 +21,8 @@ function config(updateStatusPath: string, versionFile: string): AppConfig {
|
||||
network: {
|
||||
enabled: false,
|
||||
statusPath: join(tmpdir(), "missing-network-status.json"),
|
||||
commandPath: join(tmpdir(), "network-command.json")
|
||||
commandPath: join(tmpdir(), "network-command.json"),
|
||||
configurationRequestPath: join(tmpdir(), "network-configuration.json")
|
||||
},
|
||||
adb: { enabled: false, executable: "adb", serial: null, timeoutMs: 3_000 }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user