mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 15:38:25 +00:00
fix: Device Token Scope Escalation via Rotate Endpoint (#20703)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 4f2c2ecef4
Co-authored-by: coygeek <65363919+coygeek@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
This commit is contained in:
@@ -97,7 +97,7 @@ describe("device pairing tokens", () => {
|
||||
expect(Buffer.from(token, "base64url")).toHaveLength(32);
|
||||
});
|
||||
|
||||
test("preserves existing token scopes when rotating without scopes", async () => {
|
||||
test("allows down-scoping from admin and preserves approved scope baseline", async () => {
|
||||
const baseDir = await mkdtemp(join(tmpdir(), "openclaw-device-pairing-"));
|
||||
await setupPairedOperatorDevice(baseDir, ["operator.admin"]);
|
||||
|
||||
@@ -109,7 +109,8 @@ describe("device pairing tokens", () => {
|
||||
});
|
||||
let paired = await getPairedDevice("device-1", baseDir);
|
||||
expect(paired?.tokens?.operator?.scopes).toEqual(["operator.read"]);
|
||||
expect(paired?.scopes).toEqual(["operator.read"]);
|
||||
expect(paired?.scopes).toEqual(["operator.admin"]);
|
||||
expect(paired?.approvedScopes).toEqual(["operator.admin"]);
|
||||
|
||||
await rotateDeviceToken({
|
||||
deviceId: "device-1",
|
||||
@@ -120,6 +121,26 @@ describe("device pairing tokens", () => {
|
||||
expect(paired?.tokens?.operator?.scopes).toEqual(["operator.read"]);
|
||||
});
|
||||
|
||||
test("rejects scope escalation when rotating a token and leaves state unchanged", async () => {
|
||||
const baseDir = await mkdtemp(join(tmpdir(), "openclaw-device-pairing-"));
|
||||
await setupPairedOperatorDevice(baseDir, ["operator.read"]);
|
||||
const before = await getPairedDevice("device-1", baseDir);
|
||||
|
||||
const rotated = await rotateDeviceToken({
|
||||
deviceId: "device-1",
|
||||
role: "operator",
|
||||
scopes: ["operator.admin"],
|
||||
baseDir,
|
||||
});
|
||||
expect(rotated).toBeNull();
|
||||
|
||||
const after = await getPairedDevice("device-1", baseDir);
|
||||
expect(after?.tokens?.operator?.token).toEqual(before?.tokens?.operator?.token);
|
||||
expect(after?.tokens?.operator?.scopes).toEqual(["operator.read"]);
|
||||
expect(after?.scopes).toEqual(["operator.read"]);
|
||||
expect(after?.approvedScopes).toEqual(["operator.read"]);
|
||||
});
|
||||
|
||||
test("verifies token and rejects mismatches", async () => {
|
||||
const baseDir = await mkdtemp(join(tmpdir(), "openclaw-device-pairing-"));
|
||||
await setupPairedOperatorDevice(baseDir, ["operator.read"]);
|
||||
|
||||
Reference in New Issue
Block a user