Add a printer through the gateway without the cloud keeping its credential
POST /farms/:id/printers (owner) is the console's add-printer call. It needs a connected gateway and relays the printer's access code to it in a single provision_printer frame; the gateway connects to the printer to prove the code, saves it in its own database, and only then does the cloud create the printer row. A refused or timed-out add leaves no row, and a row insert that fails after the gateway said yes tells the gateway to forget the printer. The access code is held in the request and the one frame and nowhere else: not in any table, not in a log line, not in a response or an error (the gateway's error text is scrubbed of it as a second line of defence). Deleting a printer now also tells the gateway to forget it and its stored credential, best effort, so an unplugged gateway cannot block an owner. Only Bambu is accepted, because it is the only vendor with a working driver; the rest are found by discovery but cannot yet be driven. e2e-provision.sh drives a stand-in gateway over the real socket and, after adding a printer, searches every table of the database and the backend's log for the code (checked to fail when the code is logged).
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* A stand-in gateway that stays connected and answers printer provisioning,
|
||||
* for scripts/e2e-provision.sh.
|
||||
*
|
||||
* Needs FARM_ID in the environment (the hello must name the token's farm).
|
||||
*
|
||||
* Usage: bun scripts/fake-gateway-serve.ts <ws-url> <edge-jwt> <seconds> <frames-file> [refuse-access-code]
|
||||
*
|
||||
* Every provision_printer / remove_printer frame it receives is appended to
|
||||
* <frames-file> as one JSON line, so the script can prove the credential
|
||||
* arrived here. A provision whose access_code equals <refuse-access-code> is
|
||||
* answered as a failure, like a printer that rejected the login.
|
||||
*/
|
||||
import { appendFileSync } from "node:fs";
|
||||
|
||||
const [url, jwt, seconds, framesFile, refuseCode] = process.argv.slice(2);
|
||||
if (!url || !jwt || !seconds || !framesFile) {
|
||||
console.error("usage: fake-gateway-serve.ts <ws-url> <edge-jwt> <seconds> <frames-file> [refuse-code]");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const ws = new WebSocket(url, { headers: { authorization: `Bearer ${jwt}` } } as never);
|
||||
ws.onerror = () => {
|
||||
console.error("socket error");
|
||||
process.exit(1);
|
||||
};
|
||||
ws.onopen = () => {
|
||||
// farm_id is required by the hello schema; the backend checks it against the token's farm.
|
||||
ws.send(JSON.stringify({ type: "hello", gateway_id: "fake-gw", farm_id: process.env.FARM_ID }));
|
||||
console.log("ready");
|
||||
};
|
||||
ws.onmessage = (event) => {
|
||||
const message = JSON.parse(String(event.data));
|
||||
if (message.type !== "provision_printer" && message.type !== "remove_printer") return;
|
||||
appendFileSync(framesFile, JSON.stringify(message) + "\n");
|
||||
const refused = message.type === "provision_printer" && refuseCode && message.printer.access_code === refuseCode;
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "command_result",
|
||||
command_id: message.request_id,
|
||||
ok: !refused,
|
||||
...(refused ? { error: "could not connect to the printer: the access code was rejected" } : {}),
|
||||
}),
|
||||
);
|
||||
};
|
||||
setTimeout(() => process.exit(0), Number(seconds) * 1000);
|
||||
Reference in New Issue
Block a user