Extract public control plane routes
This commit is contained in:
+15
-142
@@ -27,11 +27,8 @@ import {
|
||||
parseControlPlaneDeviceAssignRequest,
|
||||
parseControlPlaneDeviceIdentifyRequest,
|
||||
parseControlPlaneDeviceRemoveRequest,
|
||||
parseControlPlaneDeviceRenameRequest,
|
||||
parseControlPlaneDeviceSessionRequest,
|
||||
parseControlPlanePublicAuthGrantRequest,
|
||||
parseControlPlanePublicAuthGrantRevokeRequest,
|
||||
parseControlPlanePublicSessionRequest,
|
||||
parseControlPlaneSurfaceSessionRequest,
|
||||
parseControlPlaneErrorsRequest,
|
||||
parseControlPlaneLogsRequest,
|
||||
@@ -39,14 +36,12 @@ import {
|
||||
parseControlPlaneReplEvalRequest,
|
||||
parseControlPlaneRunRequest,
|
||||
type ControlPlaneCutoverResponse,
|
||||
type ControlPlaneDeviceSessionResponse,
|
||||
type ControlPlaneDeviceTarget,
|
||||
type ControlPlaneDevicesResponse,
|
||||
type ControlPlaneErrorsResponse,
|
||||
type ControlPlaneLogsResponse,
|
||||
type ControlPlanePublicAuthGrantRevokeResponse,
|
||||
type ControlPlanePublicAuthGrantResponse,
|
||||
type ControlPlanePublicSessionResponse,
|
||||
type ControlPlaneReplLogEntry,
|
||||
type ControlPlaneRunResponse,
|
||||
type ControlPlaneSurfaceSessionResponse,
|
||||
@@ -87,17 +82,15 @@ import {
|
||||
import {
|
||||
createPublicAuthGrant,
|
||||
createPublicSessionToken,
|
||||
exchangePublicAuthGrant,
|
||||
loadPublicAuthGrants,
|
||||
normalizePublicAccessTarget,
|
||||
parsePublicSessionToken,
|
||||
publicSessionAllowsDeviceTarget,
|
||||
revokePublicAuthGrant,
|
||||
} from "./src/public-auth-grants.js";
|
||||
import {
|
||||
createReplManager,
|
||||
listReplSessionsForControlPlane,
|
||||
} from "./src/repl-manager.js";
|
||||
import { handlePublicControlPlaneRoute } from "./src/public-control-routes.js";
|
||||
import { createRunningPackageManager } from "./src/running-packages.js";
|
||||
import { createStateContextRegistry } from "./src/state-contexts.js";
|
||||
import { createSubscriptionManager } from "./src/subscriptions.js";
|
||||
@@ -1157,140 +1150,20 @@ if (CONTROL_PLANE_SECRET) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
request.method === "POST" &&
|
||||
request.url === CONTROL_PLANE_ROUTES.deviceSession
|
||||
) {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const params = parseControlPlaneDeviceSessionRequest(body);
|
||||
if (!params) {
|
||||
sendJson(response, 400, { error: "Invalid device session request" });
|
||||
return;
|
||||
}
|
||||
const publicSession = parsePublicSessionToken(params.sessionToken);
|
||||
if (
|
||||
!publicSession ||
|
||||
!publicSessionAllowsDeviceTarget(publicSession, params.requestedTarget)
|
||||
) {
|
||||
sendJson(response, 401, { error: "Unauthorized" });
|
||||
return;
|
||||
}
|
||||
|
||||
const device = getOrCreateDevice(params.deviceId);
|
||||
let changed = false;
|
||||
let persistedChanged = false;
|
||||
if (markDeviceSeenThisSession(device.deviceId)) {
|
||||
changed = true;
|
||||
}
|
||||
device.lastSeenAt = nowIso();
|
||||
if ((params.userAgent ?? null) !== device.lastUserAgent) {
|
||||
device.lastUserAgent = params.userAgent ?? null;
|
||||
changed = true;
|
||||
persistedChanged = true;
|
||||
}
|
||||
const nextViewport = params.viewport ?? null;
|
||||
if (JSON.stringify(device.viewport) !== JSON.stringify(nextViewport)) {
|
||||
device.viewport = nextViewport;
|
||||
changed = true;
|
||||
persistedChanged = true;
|
||||
}
|
||||
if (params.requestedTarget !== undefined) {
|
||||
const validatedTarget = tryValidateDeviceTarget(
|
||||
params.requestedTarget ?? null,
|
||||
);
|
||||
if (!validatedTarget.ok) {
|
||||
sendJson(response, 400, { error: validatedTarget.error });
|
||||
return;
|
||||
}
|
||||
if (JSON.stringify(device.assignment) !== JSON.stringify(validatedTarget.target)) {
|
||||
device.assignment = validatedTarget.target;
|
||||
changed = true;
|
||||
persistedChanged = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
if (persistedChanged) {
|
||||
saveDeviceState();
|
||||
}
|
||||
broadcastControlPlaneStatusInvalidated("devices-changed");
|
||||
sendDeviceState(device.deviceId);
|
||||
}
|
||||
|
||||
const result: ControlPlaneDeviceSessionResponse = {
|
||||
device: findDeviceForControlPlane(device.deviceId)!,
|
||||
};
|
||||
sendJson(response, 200, result);
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
request.method === "POST" &&
|
||||
request.url === CONTROL_PLANE_ROUTES.publicSession
|
||||
) {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const params = parseControlPlanePublicSessionRequest(body);
|
||||
if (!params) {
|
||||
sendJson(response, 400, { error: "Invalid public session request" });
|
||||
return;
|
||||
}
|
||||
const session = exchangePublicAuthGrant(params.authGrant);
|
||||
if (!session) {
|
||||
sendJson(response, 401, { error: "Unauthorized" });
|
||||
return;
|
||||
}
|
||||
const result: ControlPlanePublicSessionResponse = session;
|
||||
sendJson(response, 200, result);
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
request.method === "POST" &&
|
||||
request.url === CONTROL_PLANE_ROUTES.deviceRename
|
||||
) {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const params = parseControlPlaneDeviceRenameRequest(body);
|
||||
if (!params) {
|
||||
sendJson(response, 400, { error: "Invalid device rename request" });
|
||||
return;
|
||||
}
|
||||
const device = requireDevice(params.deviceId);
|
||||
if (
|
||||
!isAuthorizedControlPlaneRequest(request) &&
|
||||
!isDeviceConnected(device.deviceId)
|
||||
) {
|
||||
sendJson(response, 401, { error: "Unauthorized" });
|
||||
return;
|
||||
}
|
||||
const normalizedName = params.name?.trim().length
|
||||
? params.name.trim()
|
||||
: null;
|
||||
if (device.name !== normalizedName) {
|
||||
device.name = normalizedName;
|
||||
saveDeviceState();
|
||||
broadcastControlPlaneStatusInvalidated("devices-changed");
|
||||
sendDeviceState(device.deviceId);
|
||||
}
|
||||
sendJson(response, 200, {
|
||||
device: findDeviceForControlPlane(device.deviceId),
|
||||
});
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
if (await handlePublicControlPlaneRoute({
|
||||
broadcastDevicesChanged: () =>
|
||||
broadcastControlPlaneStatusInvalidated("devices-changed"),
|
||||
findDeviceForControlPlane,
|
||||
getOrCreateDevice,
|
||||
isDeviceConnected,
|
||||
markDeviceSeenThisSession,
|
||||
request,
|
||||
requireDevice,
|
||||
response,
|
||||
saveDeviceState,
|
||||
sendDeviceState,
|
||||
tryValidateDeviceTarget,
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import type http from "node:http";
|
||||
import {
|
||||
CONTROL_PLANE_ROUTES,
|
||||
parseControlPlaneDeviceRenameRequest,
|
||||
parseControlPlaneDeviceSessionRequest,
|
||||
parseControlPlanePublicSessionRequest,
|
||||
type ControlPlaneDevice,
|
||||
type ControlPlaneDeviceSessionResponse,
|
||||
type ControlPlanePublicSessionResponse,
|
||||
} from "@quixos/control-plane-protocol";
|
||||
import {
|
||||
isAuthorizedControlPlaneRequest,
|
||||
readJsonBody,
|
||||
sendJson,
|
||||
} from "./http.js";
|
||||
import {
|
||||
exchangePublicAuthGrant,
|
||||
parsePublicSessionToken,
|
||||
publicSessionAllowsDeviceTarget,
|
||||
} from "./public-auth-grants.js";
|
||||
import { nowIso } from "./util.js";
|
||||
|
||||
export const handlePublicControlPlaneRoute = async ({
|
||||
broadcastDevicesChanged,
|
||||
findDeviceForControlPlane,
|
||||
getOrCreateDevice,
|
||||
isDeviceConnected,
|
||||
markDeviceSeenThisSession,
|
||||
request,
|
||||
requireDevice,
|
||||
response,
|
||||
saveDeviceState,
|
||||
sendDeviceState,
|
||||
tryValidateDeviceTarget,
|
||||
}: {
|
||||
broadcastDevicesChanged: () => void;
|
||||
findDeviceForControlPlane: (deviceId: string) => ControlPlaneDevice | undefined;
|
||||
getOrCreateDevice: (deviceId: string) => any;
|
||||
isDeviceConnected: (deviceId: string) => boolean;
|
||||
markDeviceSeenThisSession: (deviceId: string) => boolean;
|
||||
request: http.IncomingMessage;
|
||||
requireDevice: (deviceId: string) => any;
|
||||
response: http.ServerResponse;
|
||||
saveDeviceState: () => void;
|
||||
sendDeviceState: (deviceId: string) => void;
|
||||
tryValidateDeviceTarget: (
|
||||
target: any,
|
||||
) =>
|
||||
| { ok: true; target: any }
|
||||
| { ok: false; error: string };
|
||||
}) => {
|
||||
if (
|
||||
request.method === "POST" &&
|
||||
request.url === CONTROL_PLANE_ROUTES.deviceSession
|
||||
) {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const params = parseControlPlaneDeviceSessionRequest(body);
|
||||
if (!params) {
|
||||
sendJson(response, 400, { error: "Invalid device session request" });
|
||||
return true;
|
||||
}
|
||||
const publicSession = parsePublicSessionToken(params.sessionToken);
|
||||
if (
|
||||
!publicSession ||
|
||||
!publicSessionAllowsDeviceTarget(publicSession, params.requestedTarget)
|
||||
) {
|
||||
sendJson(response, 401, { error: "Unauthorized" });
|
||||
return true;
|
||||
}
|
||||
|
||||
const device = getOrCreateDevice(params.deviceId);
|
||||
let changed = false;
|
||||
let persistedChanged = false;
|
||||
if (markDeviceSeenThisSession(device.deviceId)) {
|
||||
changed = true;
|
||||
}
|
||||
device.lastSeenAt = nowIso();
|
||||
if ((params.userAgent ?? null) !== device.lastUserAgent) {
|
||||
device.lastUserAgent = params.userAgent ?? null;
|
||||
changed = true;
|
||||
persistedChanged = true;
|
||||
}
|
||||
const nextViewport = params.viewport ?? null;
|
||||
if (JSON.stringify(device.viewport) !== JSON.stringify(nextViewport)) {
|
||||
device.viewport = nextViewport;
|
||||
changed = true;
|
||||
persistedChanged = true;
|
||||
}
|
||||
if (params.requestedTarget !== undefined) {
|
||||
const validatedTarget = tryValidateDeviceTarget(
|
||||
params.requestedTarget ?? null,
|
||||
);
|
||||
if (!validatedTarget.ok) {
|
||||
sendJson(response, 400, { error: validatedTarget.error });
|
||||
return true;
|
||||
}
|
||||
if (JSON.stringify(device.assignment) !== JSON.stringify(validatedTarget.target)) {
|
||||
device.assignment = validatedTarget.target;
|
||||
changed = true;
|
||||
persistedChanged = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
if (persistedChanged) {
|
||||
saveDeviceState();
|
||||
}
|
||||
broadcastDevicesChanged();
|
||||
sendDeviceState(device.deviceId);
|
||||
}
|
||||
|
||||
const result: ControlPlaneDeviceSessionResponse = {
|
||||
device: findDeviceForControlPlane(device.deviceId)!,
|
||||
};
|
||||
sendJson(response, 200, result);
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
request.method === "POST" &&
|
||||
request.url === CONTROL_PLANE_ROUTES.publicSession
|
||||
) {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const params = parseControlPlanePublicSessionRequest(body);
|
||||
if (!params) {
|
||||
sendJson(response, 400, { error: "Invalid public session request" });
|
||||
return true;
|
||||
}
|
||||
const session = exchangePublicAuthGrant(params.authGrant);
|
||||
if (!session) {
|
||||
sendJson(response, 401, { error: "Unauthorized" });
|
||||
return true;
|
||||
}
|
||||
const result: ControlPlanePublicSessionResponse = session;
|
||||
sendJson(response, 200, result);
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
request.method === "POST" &&
|
||||
request.url === CONTROL_PLANE_ROUTES.deviceRename
|
||||
) {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const params = parseControlPlaneDeviceRenameRequest(body);
|
||||
if (!params) {
|
||||
sendJson(response, 400, { error: "Invalid device rename request" });
|
||||
return true;
|
||||
}
|
||||
const device = requireDevice(params.deviceId);
|
||||
if (
|
||||
!isAuthorizedControlPlaneRequest(request) &&
|
||||
!isDeviceConnected(device.deviceId)
|
||||
) {
|
||||
sendJson(response, 401, { error: "Unauthorized" });
|
||||
return true;
|
||||
}
|
||||
const normalizedName = params.name?.trim().length
|
||||
? params.name.trim()
|
||||
: null;
|
||||
if (device.name !== normalizedName) {
|
||||
device.name = normalizedName;
|
||||
saveDeviceState();
|
||||
broadcastDevicesChanged();
|
||||
sendDeviceState(device.deviceId);
|
||||
}
|
||||
sendJson(response, 200, {
|
||||
device: findDeviceForControlPlane(device.deviceId),
|
||||
});
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
Reference in New Issue
Block a user