mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 04:20:34 +00:00
fix(pairing): mint tokens for merged device roles
This commit is contained in:
@@ -206,6 +206,33 @@ describe("device pairing tokens", () => {
|
||||
status: "approved",
|
||||
requestId: request.request.requestId,
|
||||
});
|
||||
|
||||
const paired = await getPairedDevice("device-1", baseDir);
|
||||
expect(paired && listEffectivePairedDeviceRoles(paired)).toEqual(["node", "operator"]);
|
||||
expect(paired?.tokens?.node?.scopes).toEqual([]);
|
||||
expect(paired?.tokens?.operator?.scopes).toEqual([
|
||||
"operator.read",
|
||||
"operator.talk.secrets",
|
||||
"operator.write",
|
||||
]);
|
||||
await expect(
|
||||
verifyDeviceToken({
|
||||
deviceId: "device-1",
|
||||
token: requireToken(paired?.tokens?.node?.token),
|
||||
role: "node",
|
||||
scopes: [],
|
||||
baseDir,
|
||||
}),
|
||||
).resolves.toEqual({ ok: true });
|
||||
await expect(
|
||||
verifyDeviceToken({
|
||||
deviceId: "device-1",
|
||||
token: requireToken(paired?.tokens?.operator?.token),
|
||||
role: "operator",
|
||||
scopes: ["operator.read"],
|
||||
baseDir,
|
||||
}),
|
||||
).resolves.toEqual({ ok: true });
|
||||
});
|
||||
|
||||
test("keeps superseded requests interactive when an existing pending request is interactive", async () => {
|
||||
|
||||
@@ -344,6 +344,28 @@ function buildDeviceAuthToken(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function resolveApprovedTokenScopes(params: {
|
||||
role: string;
|
||||
pending: DevicePairingPendingRequest;
|
||||
existingToken?: DeviceAuthToken;
|
||||
approvedScopes?: string[];
|
||||
existing?: PairedDevice;
|
||||
}): string[] {
|
||||
if (params.role === "operator") {
|
||||
const requestedScopes = normalizeDeviceAuthScopes(params.pending.scopes);
|
||||
if (requestedScopes.length > 0) {
|
||||
return requestedScopes;
|
||||
}
|
||||
return normalizeDeviceAuthScopes(
|
||||
params.existingToken?.scopes ??
|
||||
params.approvedScopes ??
|
||||
params.existing?.approvedScopes ??
|
||||
params.existing?.scopes,
|
||||
);
|
||||
}
|
||||
return normalizeDeviceAuthScopes(params.existingToken?.scopes);
|
||||
}
|
||||
|
||||
function resolveApprovedDeviceScopeBaseline(device: PairedDevice): string[] | null {
|
||||
const baseline = device.approvedScopes ?? device.scopes;
|
||||
if (!Array.isArray(baseline)) {
|
||||
@@ -506,19 +528,15 @@ export async function approveDevicePairing(
|
||||
pending.scopes,
|
||||
);
|
||||
const tokens = existing?.tokens ? { ...existing.tokens } : {};
|
||||
const roleForToken = normalizeRole(pending.role);
|
||||
if (roleForToken) {
|
||||
for (const roleForToken of requestedRoles) {
|
||||
const existingToken = tokens[roleForToken];
|
||||
const requestedScopes = normalizeDeviceAuthScopes(pending.scopes);
|
||||
const nextScopes =
|
||||
requestedScopes.length > 0
|
||||
? requestedScopes
|
||||
: normalizeDeviceAuthScopes(
|
||||
existingToken?.scopes ??
|
||||
approvedScopes ??
|
||||
existing?.approvedScopes ??
|
||||
existing?.scopes,
|
||||
);
|
||||
const nextScopes = resolveApprovedTokenScopes({
|
||||
role: roleForToken,
|
||||
pending,
|
||||
existingToken,
|
||||
approvedScopes,
|
||||
existing,
|
||||
});
|
||||
const now = Date.now();
|
||||
tokens[roleForToken] = {
|
||||
token: newToken(),
|
||||
|
||||
Reference in New Issue
Block a user