Add client endpoint to network log

This commit is contained in:
Owen
2026-05-08 17:04:58 -07:00
parent 10f95896aa
commit 114486608e
7 changed files with 46 additions and 31 deletions

View File

@@ -332,6 +332,7 @@ export const connectionAuditLog = pgTable(
clientId: integer("clientId").references(() => clients.clientId, { clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade" onDelete: "cascade"
}), }),
clientEndpoint: text("clientEndpoint"),
userId: text("userId").references(() => users.userId, { userId: text("userId").references(() => users.userId, {
onDelete: "cascade" onDelete: "cascade"
}), }),

View File

@@ -332,6 +332,7 @@ export const connectionAuditLog = sqliteTable(
clientId: integer("clientId").references(() => clients.clientId, { clientId: integer("clientId").references(() => clients.clientId, {
onDelete: "cascade" onDelete: "cascade"
}), }),
clientEndpoint: text("clientEndpoint"),
userId: text("userId").references(() => users.userId, { userId: text("userId").references(() => users.userId, {
onDelete: "cascade" onDelete: "cascade"
}), }),

View File

@@ -46,6 +46,7 @@ export interface ConnectionLogRecord {
orgId: string; orgId: string;
siteId: number; siteId: number;
clientId: number | null; clientId: number | null;
clientEndpoint: string | null;
userId: string | null; userId: string | null;
sourceAddr: string; sourceAddr: string;
destAddr: string; destAddr: string;

View File

@@ -124,15 +124,11 @@ function getWhere(data: Q) {
data.clientId data.clientId
? eq(connectionAuditLog.clientId, data.clientId) ? eq(connectionAuditLog.clientId, data.clientId)
: undefined, : undefined,
data.siteId data.siteId ? eq(connectionAuditLog.siteId, data.siteId) : undefined,
? eq(connectionAuditLog.siteId, data.siteId)
: undefined,
data.siteResourceId data.siteResourceId
? eq(connectionAuditLog.siteResourceId, data.siteResourceId) ? eq(connectionAuditLog.siteResourceId, data.siteResourceId)
: undefined, : undefined,
data.userId data.userId ? eq(connectionAuditLog.userId, data.userId) : undefined
? eq(connectionAuditLog.userId, data.userId)
: undefined
); );
} }
@@ -144,6 +140,7 @@ export function queryConnection(data: Q) {
orgId: connectionAuditLog.orgId, orgId: connectionAuditLog.orgId,
siteId: connectionAuditLog.siteId, siteId: connectionAuditLog.siteId,
clientId: connectionAuditLog.clientId, clientId: connectionAuditLog.clientId,
clientEndpoint: connectionAuditLog.clientEndpoint,
userId: connectionAuditLog.userId, userId: connectionAuditLog.userId,
sourceAddr: connectionAuditLog.sourceAddr, sourceAddr: connectionAuditLog.sourceAddr,
destAddr: connectionAuditLog.destAddr, destAddr: connectionAuditLog.destAddr,
@@ -203,10 +200,7 @@ async function enrichWithDetails(
]; ];
// Fetch resource details from main database // Fetch resource details from main database
const resourceMap = new Map< const resourceMap = new Map<number, { name: string; niceId: string }>();
number,
{ name: string; niceId: string }
>();
if (siteResourceIds.length > 0) { if (siteResourceIds.length > 0) {
const resourceDetails = await primaryDb const resourceDetails = await primaryDb
.select({ .select({
@@ -268,10 +262,7 @@ async function enrichWithDetails(
} }
// Fetch user details from main database // Fetch user details from main database
const userMap = new Map< const userMap = new Map<string, { email: string | null }>();
string,
{ email: string | null }
>();
if (userIds.length > 0) { if (userIds.length > 0) {
const userDetails = await primaryDb const userDetails = await primaryDb
.select({ .select({
@@ -290,29 +281,25 @@ async function enrichWithDetails(
return logs.map((log) => ({ return logs.map((log) => ({
...log, ...log,
resourceName: log.siteResourceId resourceName: log.siteResourceId
? resourceMap.get(log.siteResourceId)?.name ?? null ? (resourceMap.get(log.siteResourceId)?.name ?? null)
: null, : null,
resourceNiceId: log.siteResourceId resourceNiceId: log.siteResourceId
? resourceMap.get(log.siteResourceId)?.niceId ?? null ? (resourceMap.get(log.siteResourceId)?.niceId ?? null)
: null,
siteName: log.siteId
? siteMap.get(log.siteId)?.name ?? null
: null, : null,
siteName: log.siteId ? (siteMap.get(log.siteId)?.name ?? null) : null,
siteNiceId: log.siteId siteNiceId: log.siteId
? siteMap.get(log.siteId)?.niceId ?? null ? (siteMap.get(log.siteId)?.niceId ?? null)
: null, : null,
clientName: log.clientId clientName: log.clientId
? clientMap.get(log.clientId)?.name ?? null ? (clientMap.get(log.clientId)?.name ?? null)
: null, : null,
clientNiceId: log.clientId clientNiceId: log.clientId
? clientMap.get(log.clientId)?.niceId ?? null ? (clientMap.get(log.clientId)?.niceId ?? null)
: null, : null,
clientType: log.clientId clientType: log.clientId
? clientMap.get(log.clientId)?.type ?? null ? (clientMap.get(log.clientId)?.type ?? null)
: null, : null,
userEmail: log.userId userEmail: log.userId ? (userMap.get(log.userId)?.email ?? null) : null
? userMap.get(log.userId)?.email ?? null
: null
})); }));
} }
@@ -521,4 +508,4 @@ export async function queryConnectionAuditLogs(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred") createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
); );
} }
} }

View File

@@ -11,7 +11,7 @@
* This file is not licensed under the AGPLv3. * This file is not licensed under the AGPLv3.
*/ */
import { db } from "@server/db"; import { clientSitesAssociationsCache, db } from "@server/db";
import { MessageHandler } from "@server/routers/ws"; import { MessageHandler } from "@server/routers/ws";
import { sites, Newt, clients, orgs } from "@server/db"; import { sites, Newt, clients, orgs } from "@server/db";
import { and, eq, inArray } from "drizzle-orm"; import { and, eq, inArray } from "drizzle-orm";
@@ -146,7 +146,11 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
// each unique sourceAddr + the org's CIDR suffix and do a targeted IN query. // each unique sourceAddr + the org's CIDR suffix and do a targeted IN query.
const ipToClient = new Map< const ipToClient = new Map<
string, string,
{ clientId: number; userId: string | null } {
clientId: number;
userId: string | null;
clientEndpoint: string | null;
}
>(); >();
if (cidrSuffix) { if (cidrSuffix) {
@@ -172,9 +176,21 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
.select({ .select({
clientId: clients.clientId, clientId: clients.clientId,
userId: clients.userId, userId: clients.userId,
subnet: clients.subnet subnet: clients.subnet,
clientEndpoint: clientSitesAssociationsCache.endpoint
}) })
.from(clients) .from(clients)
.leftJoin(
// this should be one to one
clientSitesAssociationsCache,
and(
eq(
clients.clientId,
clientSitesAssociationsCache.clientId
),
eq(clientSitesAssociationsCache.siteId, newt.siteId)
)
)
.where( .where(
and( and(
eq(clients.orgId, orgId), eq(clients.orgId, orgId),
@@ -189,7 +205,8 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
); );
ipToClient.set(ip, { ipToClient.set(ip, {
clientId: c.clientId, clientId: c.clientId,
userId: c.userId userId: c.userId,
clientEndpoint: c.clientEndpoint
}); });
} }
} }
@@ -234,6 +251,7 @@ export const handleConnectionLogMessage: MessageHandler = async (context) => {
orgId, orgId,
siteId: newt.siteId, siteId: newt.siteId,
clientId: clientInfo?.clientId ?? null, clientId: clientInfo?.clientId ?? null,
clientEndpoint: clientInfo?.clientEndpoint ?? null,
userId: clientInfo?.userId ?? null, userId: clientInfo?.userId ?? null,
sourceAddr: session.sourceAddr, sourceAddr: session.sourceAddr,
destAddr: session.destAddr, destAddr: session.destAddr,

View File

@@ -100,6 +100,7 @@ export type QueryConnectionAuditLogResponse = {
orgId: string | null; orgId: string | null;
siteId: number | null; siteId: number | null;
clientId: number | null; clientId: number | null;
clientEndpoint: string | null;
userId: string | null; userId: string | null;
sourceAddr: string; sourceAddr: string;
destAddr: string; destAddr: string;

View File

@@ -645,6 +645,12 @@ export default function ConnectionLogsPage() {
</span> </span>
)} )}
</div>*/} </div>*/}
<div>
<strong>Client Endpoint:</strong>{" "}
<span className="font-mono">
{row.clientEndpoint ?? "-"}
</span>
</div>
<div> <div>
<strong>Site:</strong> {row.siteName ?? "-"} <strong>Site:</strong> {row.siteName ?? "-"}
{row.siteNiceId && ( {row.siteNiceId && (