mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
refactor(gateway): share control-plane identity normalization
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// Gateway control-plane audit helpers.
|
||||
// Extracts stable actor identity and compact changed-path summaries for audit logs.
|
||||
import { normalizeControlPlaneIdentityPart } from "./control-plane-identity.js";
|
||||
import type { GatewayClient } from "./server-methods/types.js";
|
||||
|
||||
/** Stable actor fields included in control-plane audit and rate-limit logs. */
|
||||
@@ -10,21 +11,13 @@ export type ControlPlaneActor = {
|
||||
connId: string;
|
||||
};
|
||||
|
||||
function normalizePart(value: unknown, fallback: string): string {
|
||||
if (typeof value !== "string") {
|
||||
return fallback;
|
||||
}
|
||||
const normalized = value.trim();
|
||||
return normalized.length > 0 ? normalized : fallback;
|
||||
}
|
||||
|
||||
/** Extracts audit identity from a possibly missing or partially connected client. */
|
||||
export function resolveControlPlaneActor(client: GatewayClient | null): ControlPlaneActor {
|
||||
return {
|
||||
actor: normalizePart(client?.connect?.client?.id, "unknown-actor"),
|
||||
deviceId: normalizePart(client?.connect?.device?.id, "unknown-device"),
|
||||
clientIp: normalizePart(client?.clientIp, "unknown-ip"),
|
||||
connId: normalizePart(client?.connId, "unknown-conn"),
|
||||
actor: normalizeControlPlaneIdentityPart(client?.connect?.client?.id, "unknown-actor"),
|
||||
deviceId: normalizeControlPlaneIdentityPart(client?.connect?.device?.id, "unknown-device"),
|
||||
clientIp: normalizeControlPlaneIdentityPart(client?.clientIp, "unknown-ip"),
|
||||
connId: normalizeControlPlaneIdentityPart(client?.connId, "unknown-conn"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/** Normalizes an optional control-plane identity field without creating empty keys. */
|
||||
export function normalizeControlPlaneIdentityPart(value: unknown, fallback: string): string {
|
||||
if (typeof value !== "string") {
|
||||
return fallback;
|
||||
}
|
||||
const normalized = value.trim();
|
||||
return normalized.length > 0 ? normalized : fallback;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// Control-plane rate limiting bounds write-side RPC attempts per device/IP and
|
||||
// caps bucket growth against unique-key memory pressure.
|
||||
import { normalizeControlPlaneIdentityPart } from "./control-plane-identity.js";
|
||||
import type { GatewayClient } from "./server-methods/types.js";
|
||||
|
||||
const CONTROL_PLANE_RATE_LIMIT_MAX_REQUESTS = 3;
|
||||
@@ -16,21 +17,13 @@ type Bucket = {
|
||||
|
||||
const controlPlaneBuckets = new Map<string, Bucket>();
|
||||
|
||||
function normalizePart(value: unknown, fallback: string): string {
|
||||
if (typeof value !== "string") {
|
||||
return fallback;
|
||||
}
|
||||
const normalized = value.trim();
|
||||
return normalized.length > 0 ? normalized : fallback;
|
||||
}
|
||||
|
||||
/** Builds a stable throttle key while avoiding shared fallback buckets for anonymous clients. */
|
||||
export function resolveControlPlaneRateLimitKey(client: GatewayClient | null): string {
|
||||
const deviceId = normalizePart(client?.connect?.device?.id, "unknown-device");
|
||||
const clientIp = normalizePart(client?.clientIp, "unknown-ip");
|
||||
const deviceId = normalizeControlPlaneIdentityPart(client?.connect?.device?.id, "unknown-device");
|
||||
const clientIp = normalizeControlPlaneIdentityPart(client?.clientIp, "unknown-ip");
|
||||
if (deviceId === "unknown-device" && clientIp === "unknown-ip") {
|
||||
// Last-resort fallback: avoid cross-client contention when upstream identity is missing.
|
||||
const connId = normalizePart(client?.connId, "");
|
||||
const connId = normalizeControlPlaneIdentityPart(client?.connId, "");
|
||||
if (connId) {
|
||||
return `${deviceId}|${clientIp}|conn=${connId}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user