import path from "node:path" ;
import { describe, expect, it } from "vitest" ;
import { withTempDir } from "../test-utils/temp-dir.js" ;
import {
deriveDeviceIdFromPublicKey,
loadOrCreateDeviceIdentity,
normalizeDevicePublicKeyBase64Url,
publicKeyRawBase64UrlFromPem,
signDevicePayload,
verifyDeviceSignature,
} from "./device-identity.js" ;
async function withIdentity(
run: (identity: ReturnType<typeof loadOrCreateDeviceIdentity>) => void ,
) {
await withTempDir("openclaw-device-identity-" , async (dir) => {
const identity = loadOrCreateDeviceIdentity(path.join(dir, "device.json" ));
run(identity);
});
}
describe("device identity crypto helpers" , () => {
it("derives the same canonical raw key and device id from pem and encoded public keys" , async () => {
await withIdentity((identity) => {
const publicKeyRaw = publicKeyRawBase64UrlFromPem(identity.publicKeyPem);
const paddedBase64 = `${publicKeyRaw.replaceAll("-" , "+" ).replaceAll("_" , "/" )}==`;
expect(normalizeDevicePublicKeyBase64Url(identity.publicKeyPem)).toBe(publicKeyRaw);
expect(normalizeDevicePublicKeyBase64Url(paddedBase64)).toBe(publicKeyRaw);
expect(deriveDeviceIdFromPublicKey(identity.publicKeyPem)).toBe(identity.deviceId);
expect(deriveDeviceIdFromPublicKey(publicKeyRaw)).toBe(identity.deviceId);
});
});
it("signs payloads that verify against pem and raw public key forms" , async () => {
await withIdentity((identity) => {
const payload = JSON.stringify({
action: "system.run" ,
ts: 1234 ,
});
const signature = signDevicePayload(identity.privateKeyPem, payload);
const publicKeyRaw = publicKeyRawBase64UrlFromPem(identity.publicKeyPem);
expect(verifyDeviceSignature(identity.publicKeyPem, payload, signature)).toBe(true );
expect(verifyDeviceSignature(publicKeyRaw, payload, signature)).toBe(true );
expect(verifyDeviceSignature(publicKeyRaw, `${payload}!`, signature)).toBe(false );
});
});
it("fails closed for invalid public keys and signatures" , async () => {
await withIdentity((identity) => {
const payload = "hello" ;
const signature = signDevicePayload(identity.privateKeyPem, payload);
expect(normalizeDevicePublicKeyBase64Url("-----BEGIN PUBLIC KEY-----broken" )).toBeNull();
expect(deriveDeviceIdFromPublicKey("%%%" )).toBeNull();
expect(verifyDeviceSignature("%%%invalid%%%" , payload, signature)).toBe(false );
expect(verifyDeviceSignature(identity.publicKeyPem, payload, "%%%invalid%%%" )).toBe(false );
});
});
});
Messung V0.5 in Prozent C=100 H=100 G=100
[Verzeichnis aufwärts0.13unsichere VerbindungÜbersetzung europäischer Sprachen durch Browser2026-09-27]