From 1c7ca391a8f796185b85b5063b65a9086df07b2d Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 12 Mar 2026 22:36:37 +0000 Subject: [PATCH] refactor: trim bootstrap token metadata --- extensions/device-pair/index.ts | 9 +-------- src/infra/device-bootstrap.test.ts | 18 +++++++++++++++++- src/infra/device-bootstrap.ts | 17 ----------------- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/extensions/device-pair/index.ts b/extensions/device-pair/index.ts index 62977a66e..67a50e873 100644 --- a/extensions/device-pair/index.ts +++ b/extensions/device-pair/index.ts @@ -405,14 +405,7 @@ export default function register(api: OpenClawPluginApi) { const payload: SetupPayload = { url: urlResult.url, - bootstrapToken: ( - await issueDeviceBootstrapToken({ - channel: ctx.channel, - senderId: ctx.senderId ?? ctx.from ?? ctx.to, - accountId: ctx.accountId, - threadId: ctx.messageThreadId != null ? String(ctx.messageThreadId) : undefined, - }) - ).token, + bootstrapToken: (await issueDeviceBootstrapToken()).token, }; if (action === "qr") { diff --git a/src/infra/device-bootstrap.test.ts b/src/infra/device-bootstrap.test.ts index b5f64790d..e20aafab9 100644 --- a/src/infra/device-bootstrap.test.ts +++ b/src/infra/device-bootstrap.test.ts @@ -1,4 +1,4 @@ -import { mkdtemp, rm } from "node:fs/promises"; +import { mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it, vi } from "vitest"; @@ -95,4 +95,20 @@ describe("device bootstrap tokens", () => { }), ).resolves.toEqual({ ok: false, reason: "bootstrap_token_invalid" }); }); + + it("persists only token state that verification actually consumes", async () => { + const baseDir = await createBaseDir(); + const issued = await issueDeviceBootstrapToken({ baseDir }); + const raw = await readFile(join(baseDir, "devices", "bootstrap.json"), "utf8"); + const state = JSON.parse(raw) as Record>; + const record = state[issued.token]; + + expect(record).toMatchObject({ + token: issued.token, + }); + expect(record).not.toHaveProperty("channel"); + expect(record).not.toHaveProperty("senderId"); + expect(record).not.toHaveProperty("accountId"); + expect(record).not.toHaveProperty("threadId"); + }); }); diff --git a/src/infra/device-bootstrap.ts b/src/infra/device-bootstrap.ts index 438500f4f..9f763b50c 100644 --- a/src/infra/device-bootstrap.ts +++ b/src/infra/device-bootstrap.ts @@ -17,10 +17,6 @@ export type DeviceBootstrapTokenRecord = { publicKey?: string; roles?: string[]; scopes?: string[]; - channel?: string; - senderId?: string; - accountId?: string; - threadId?: string; issuedAtMs: number; lastUsedAtMs?: number; }; @@ -29,11 +25,6 @@ type DeviceBootstrapStateFile = Record; const withLock = createAsyncLock(); -function normalizeOptionalString(value: string | undefined): string | undefined { - const trimmed = value?.trim(); - return trimmed ? trimmed : undefined; -} - function mergeRoles(existing: string[] | undefined, role: string): string[] { const out = new Set(existing ?? []); const trimmed = role.trim(); @@ -80,10 +71,6 @@ async function persistState(state: DeviceBootstrapStateFile, baseDir?: string): export async function issueDeviceBootstrapToken( params: { - channel?: string; - senderId?: string; - accountId?: string; - threadId?: string; baseDir?: string; } = {}, ): Promise<{ token: string; expiresAtMs: number }> { @@ -94,10 +81,6 @@ export async function issueDeviceBootstrapToken( state[token] = { token, ts: issuedAtMs, - channel: normalizeOptionalString(params.channel), - senderId: normalizeOptionalString(params.senderId), - accountId: normalizeOptionalString(params.accountId), - threadId: normalizeOptionalString(params.threadId), issuedAtMs, }; await persistState(state, params.baseDir);