mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
feat(fingerprint): consolidate posture checks into fingerprint table
This commit is contained in:
committed by
Owen Schwartz
parent
1f077d7ec2
commit
3ce1afbcc9
@@ -726,6 +726,99 @@ export const clientPostureSnapshots = pgTable("clientPostureSnapshots", {
|
|||||||
onDelete: "cascade"
|
onDelete: "cascade"
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
collectedAt: integer("collectedAt").notNull()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const olms = pgTable("olms", {
|
||||||
|
olmId: varchar("id").primaryKey(),
|
||||||
|
secretHash: varchar("secretHash").notNull(),
|
||||||
|
dateCreated: varchar("dateCreated").notNull(),
|
||||||
|
version: text("version"),
|
||||||
|
agent: text("agent"),
|
||||||
|
name: varchar("name"),
|
||||||
|
clientId: integer("clientId").references(() => clients.clientId, {
|
||||||
|
// we will switch this depending on the current org it wants to connect to
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
userId: text("userId").references(() => users.userId, {
|
||||||
|
// optionally tied to a user and in this case delete when the user deletes
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
archived: boolean("archived").notNull().default(false)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const currentFingerprint = pgTable("currentFingerprint", {
|
||||||
|
fingerprintId: serial("id").primaryKey(),
|
||||||
|
|
||||||
|
olmId: text("olmId")
|
||||||
|
.references(() => olms.olmId, { onDelete: "cascade" })
|
||||||
|
.notNull(),
|
||||||
|
|
||||||
|
firstSeen: integer("firstSeen").notNull(),
|
||||||
|
lastSeen: integer("lastSeen").notNull(),
|
||||||
|
lastCollectedAt: integer("lastCollectedAt").notNull(),
|
||||||
|
|
||||||
|
username: text("username"),
|
||||||
|
hostname: text("hostname"),
|
||||||
|
platform: text("platform"),
|
||||||
|
osVersion: text("osVersion"),
|
||||||
|
kernelVersion: text("kernelVersion"),
|
||||||
|
arch: text("arch"),
|
||||||
|
deviceModel: text("deviceModel"),
|
||||||
|
serialNumber: text("serialNumber"),
|
||||||
|
platformFingerprint: varchar("platformFingerprint"),
|
||||||
|
|
||||||
|
// Platform-agnostic checks
|
||||||
|
|
||||||
|
biometricsEnabled: boolean("biometricsEnabled").notNull().default(false),
|
||||||
|
diskEncrypted: boolean("diskEncrypted").notNull().default(false),
|
||||||
|
firewallEnabled: boolean("firewallEnabled").notNull().default(false),
|
||||||
|
autoUpdatesEnabled: boolean("autoUpdatesEnabled").notNull().default(false),
|
||||||
|
tpmAvailable: boolean("tpmAvailable").notNull().default(false),
|
||||||
|
|
||||||
|
// Windows-specific posture check information
|
||||||
|
|
||||||
|
windowsDefenderEnabled: boolean("windowsDefenderEnabled")
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
|
||||||
|
// macOS-specific posture check information
|
||||||
|
|
||||||
|
macosSipEnabled: boolean("macosSipEnabled").notNull().default(false),
|
||||||
|
macosGatekeeperEnabled: boolean("macosGatekeeperEnabled")
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
macosFirewallStealthMode: boolean("macosFirewallStealthMode")
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
|
||||||
|
// Linux-specific posture check information
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: boolean("linuxAppArmorEnabled")
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
linuxSELinuxEnabled: boolean("linuxSELinuxEnabled").notNull().default(false)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fingerprintSnapshots = pgTable("fingerprintSnapshots", {
|
||||||
|
snapshotId: serial("id").primaryKey(),
|
||||||
|
|
||||||
|
fingerprintId: integer("fingerprintId")
|
||||||
|
.references(() => currentFingerprint.fingerprintId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
})
|
||||||
|
.notNull(),
|
||||||
|
|
||||||
|
username: text("username"),
|
||||||
|
hostname: text("hostname"),
|
||||||
|
platform: text("platform"),
|
||||||
|
osVersion: text("osVersion"),
|
||||||
|
kernelVersion: text("kernelVersion"),
|
||||||
|
arch: text("arch"),
|
||||||
|
deviceModel: text("deviceModel"),
|
||||||
|
serialNumber: text("serialNumber"),
|
||||||
|
platformFingerprint: varchar("platformFingerprint"),
|
||||||
|
|
||||||
// Platform-agnostic checks
|
// Platform-agnostic checks
|
||||||
|
|
||||||
biometricsEnabled: boolean("biometricsEnabled").notNull().default(false),
|
biometricsEnabled: boolean("biometricsEnabled").notNull().default(false),
|
||||||
@@ -759,67 +852,6 @@ export const clientPostureSnapshots = pgTable("clientPostureSnapshots", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
.default(false),
|
.default(false),
|
||||||
|
|
||||||
collectedAt: integer("collectedAt").notNull()
|
|
||||||
});
|
|
||||||
|
|
||||||
export const olms = pgTable("olms", {
|
|
||||||
olmId: varchar("id").primaryKey(),
|
|
||||||
secretHash: varchar("secretHash").notNull(),
|
|
||||||
dateCreated: varchar("dateCreated").notNull(),
|
|
||||||
version: text("version"),
|
|
||||||
agent: text("agent"),
|
|
||||||
name: varchar("name"),
|
|
||||||
clientId: integer("clientId").references(() => clients.clientId, {
|
|
||||||
// we will switch this depending on the current org it wants to connect to
|
|
||||||
onDelete: "set null"
|
|
||||||
}),
|
|
||||||
userId: text("userId").references(() => users.userId, {
|
|
||||||
// optionally tied to a user and in this case delete when the user deletes
|
|
||||||
onDelete: "cascade"
|
|
||||||
}),
|
|
||||||
archived: boolean("archived").notNull().default(false)
|
|
||||||
});
|
|
||||||
|
|
||||||
export const currentFingerprint = pgTable("currentFingerprint", {
|
|
||||||
fingerprintId: serial("id").primaryKey(),
|
|
||||||
|
|
||||||
olmId: text("olmId")
|
|
||||||
.references(() => olms.olmId, { onDelete: "cascade" })
|
|
||||||
.notNull(),
|
|
||||||
|
|
||||||
firstSeen: integer("firstSeen").notNull(),
|
|
||||||
lastSeen: integer("lastSeen").notNull(),
|
|
||||||
|
|
||||||
username: text("username"),
|
|
||||||
hostname: text("hostname"),
|
|
||||||
platform: text("platform"),
|
|
||||||
osVersion: text("osVersion"),
|
|
||||||
kernelVersion: text("kernelVersion"),
|
|
||||||
arch: text("arch"),
|
|
||||||
deviceModel: text("deviceModel"),
|
|
||||||
serialNumber: text("serialNumber"),
|
|
||||||
platformFingerprint: varchar("platformFingerprint")
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fingerprintSnapshots = pgTable("fingerprintSnapshots", {
|
|
||||||
snapshotId: serial("id").primaryKey(),
|
|
||||||
|
|
||||||
fingerprintId: integer("fingerprintId")
|
|
||||||
.references(() => currentFingerprint.fingerprintId, {
|
|
||||||
onDelete: "cascade"
|
|
||||||
})
|
|
||||||
.notNull(),
|
|
||||||
|
|
||||||
username: text("username"),
|
|
||||||
hostname: text("hostname"),
|
|
||||||
platform: text("platform"),
|
|
||||||
osVersion: text("osVersion"),
|
|
||||||
kernelVersion: text("kernelVersion"),
|
|
||||||
arch: text("arch"),
|
|
||||||
deviceModel: text("deviceModel"),
|
|
||||||
serialNumber: text("serialNumber"),
|
|
||||||
platformFingerprint: varchar("platformFingerprint"),
|
|
||||||
|
|
||||||
hash: text("hash").notNull(),
|
hash: text("hash").notNull(),
|
||||||
collectedAt: integer("collectedAt").notNull()
|
collectedAt: integer("collectedAt").notNull()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -416,12 +416,117 @@ export const clientSiteResourcesAssociationsCache = sqliteTable(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const clientPostureSnapshots = sqliteTable("clientPostureSnapshots", {
|
export const olms = sqliteTable("olms", {
|
||||||
snapshotId: integer("snapshotId").primaryKey({ autoIncrement: true }),
|
olmId: text("id").primaryKey(),
|
||||||
|
secretHash: text("secretHash").notNull(),
|
||||||
|
dateCreated: text("dateCreated").notNull(),
|
||||||
|
version: text("version"),
|
||||||
|
agent: text("agent"),
|
||||||
|
name: text("name"),
|
||||||
clientId: integer("clientId").references(() => clients.clientId, {
|
clientId: integer("clientId").references(() => clients.clientId, {
|
||||||
|
// we will switch this depending on the current org it wants to connect to
|
||||||
|
onDelete: "set null"
|
||||||
|
}),
|
||||||
|
userId: text("userId").references(() => users.userId, {
|
||||||
|
// optionally tied to a user and in this case delete when the user deletes
|
||||||
onDelete: "cascade"
|
onDelete: "cascade"
|
||||||
}),
|
}),
|
||||||
|
archived: integer("archived", { mode: "boolean" }).notNull().default(false)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const currentFingerprint = sqliteTable("currentFingerprint", {
|
||||||
|
fingerprintId: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
|
|
||||||
|
olmId: text("olmId")
|
||||||
|
.references(() => olms.olmId, { onDelete: "cascade" })
|
||||||
|
.notNull(),
|
||||||
|
|
||||||
|
firstSeen: integer("firstSeen").notNull(),
|
||||||
|
lastSeen: integer("lastSeen").notNull(),
|
||||||
|
lastCollectedAt: integer("lastCollectedAt").notNull(),
|
||||||
|
|
||||||
|
username: text("username"),
|
||||||
|
hostname: text("hostname"),
|
||||||
|
platform: text("platform"),
|
||||||
|
osVersion: text("osVersion"),
|
||||||
|
kernelVersion: text("kernelVersion"),
|
||||||
|
arch: text("arch"),
|
||||||
|
deviceModel: text("deviceModel"),
|
||||||
|
serialNumber: text("serialNumber"),
|
||||||
|
platformFingerprint: text("platformFingerprint"),
|
||||||
|
|
||||||
|
// Platform-agnostic checks
|
||||||
|
|
||||||
|
biometricsEnabled: integer("biometricsEnabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
diskEncrypted: integer("diskEncrypted", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
firewallEnabled: integer("firewallEnabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
autoUpdatesEnabled: integer("autoUpdatesEnabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
tpmAvailable: integer("tpmAvailable", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
|
||||||
|
// Windows-specific posture check information
|
||||||
|
|
||||||
|
windowsDefenderEnabled: integer("windowsDefenderEnabled", {
|
||||||
|
mode: "boolean"
|
||||||
|
})
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
|
||||||
|
// macOS-specific posture check information
|
||||||
|
|
||||||
|
macosSipEnabled: integer("macosSipEnabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
macosGatekeeperEnabled: integer("macosGatekeeperEnabled", {
|
||||||
|
mode: "boolean"
|
||||||
|
})
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
macosFirewallStealthMode: integer("macosFirewallStealthMode", {
|
||||||
|
mode: "boolean"
|
||||||
|
})
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
|
||||||
|
// Linux-specific posture check information
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: integer("linuxAppArmorEnabled", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false),
|
||||||
|
linuxSELinuxEnabled: integer("linuxSELinuxEnabled", {
|
||||||
|
mode: "boolean"
|
||||||
|
})
|
||||||
|
.notNull()
|
||||||
|
.default(false)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fingerprintSnapshots = sqliteTable("fingerprintSnapshots", {
|
||||||
|
snapshotId: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
|
|
||||||
|
fingerprintId: integer("fingerprintId")
|
||||||
|
.references(() => currentFingerprint.fingerprintId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
})
|
||||||
|
.notNull(),
|
||||||
|
|
||||||
|
username: text("username"),
|
||||||
|
hostname: text("hostname"),
|
||||||
|
platform: text("platform"),
|
||||||
|
osVersion: text("osVersion"),
|
||||||
|
kernelVersion: text("kernelVersion"),
|
||||||
|
arch: text("arch"),
|
||||||
|
deviceModel: text("deviceModel"),
|
||||||
|
serialNumber: text("serialNumber"),
|
||||||
|
platformFingerprint: text("platformFingerprint"),
|
||||||
|
|
||||||
// Platform-agnostic checks
|
// Platform-agnostic checks
|
||||||
|
|
||||||
@@ -476,67 +581,6 @@ export const clientPostureSnapshots = sqliteTable("clientPostureSnapshots", {
|
|||||||
.notNull()
|
.notNull()
|
||||||
.default(false),
|
.default(false),
|
||||||
|
|
||||||
collectedAt: integer("collectedAt").notNull()
|
|
||||||
});
|
|
||||||
|
|
||||||
export const olms = sqliteTable("olms", {
|
|
||||||
olmId: text("id").primaryKey(),
|
|
||||||
secretHash: text("secretHash").notNull(),
|
|
||||||
dateCreated: text("dateCreated").notNull(),
|
|
||||||
version: text("version"),
|
|
||||||
agent: text("agent"),
|
|
||||||
name: text("name"),
|
|
||||||
clientId: integer("clientId").references(() => clients.clientId, {
|
|
||||||
// we will switch this depending on the current org it wants to connect to
|
|
||||||
onDelete: "set null"
|
|
||||||
}),
|
|
||||||
userId: text("userId").references(() => users.userId, {
|
|
||||||
// optionally tied to a user and in this case delete when the user deletes
|
|
||||||
onDelete: "cascade"
|
|
||||||
}),
|
|
||||||
archived: integer("archived", { mode: "boolean" }).notNull().default(false)
|
|
||||||
});
|
|
||||||
|
|
||||||
export const currentFingerprint = sqliteTable("currentFingerprint", {
|
|
||||||
fingerprintId: integer("id").primaryKey({ autoIncrement: true }),
|
|
||||||
|
|
||||||
olmId: text("olmId")
|
|
||||||
.references(() => olms.olmId, { onDelete: "cascade" })
|
|
||||||
.notNull(),
|
|
||||||
|
|
||||||
firstSeen: integer("firstSeen").notNull(),
|
|
||||||
lastSeen: integer("lastSeen").notNull(),
|
|
||||||
|
|
||||||
username: text("username"),
|
|
||||||
hostname: text("hostname"),
|
|
||||||
platform: text("platform"),
|
|
||||||
osVersion: text("osVersion"),
|
|
||||||
kernelVersion: text("kernelVersion"),
|
|
||||||
arch: text("arch"),
|
|
||||||
deviceModel: text("deviceModel"),
|
|
||||||
serialNumber: text("serialNumber"),
|
|
||||||
platformFingerprint: text("platformFingerprint")
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fingerprintSnapshots = sqliteTable("fingerprintSnapshots", {
|
|
||||||
snapshotId: integer("id").primaryKey({ autoIncrement: true }),
|
|
||||||
|
|
||||||
fingerprintId: integer("fingerprintId")
|
|
||||||
.references(() => currentFingerprint.fingerprintId, {
|
|
||||||
onDelete: "cascade"
|
|
||||||
})
|
|
||||||
.notNull(),
|
|
||||||
|
|
||||||
username: text("username"),
|
|
||||||
hostname: text("hostname"),
|
|
||||||
platform: text("platform"),
|
|
||||||
osVersion: text("osVersion"),
|
|
||||||
kernelVersion: text("kernelVersion"),
|
|
||||||
arch: text("arch"),
|
|
||||||
deviceModel: text("deviceModel"),
|
|
||||||
serialNumber: text("serialNumber"),
|
|
||||||
platformFingerprint: text("platformFingerprint"),
|
|
||||||
|
|
||||||
hash: text("hash").notNull(),
|
hash: text("hash").notNull(),
|
||||||
collectedAt: integer("collectedAt").notNull()
|
collectedAt: integer("collectedAt").notNull()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,17 +3,32 @@ import { encodeHexLowerCase } from "@oslojs/encoding";
|
|||||||
import { currentFingerprint, db, fingerprintSnapshots, Olm } from "@server/db";
|
import { currentFingerprint, db, fingerprintSnapshots, Olm } from "@server/db";
|
||||||
import { desc, eq } from "drizzle-orm";
|
import { desc, eq } from "drizzle-orm";
|
||||||
|
|
||||||
function fingerprintHash(fp: any): string {
|
function fingerprintSnapshotHash(fingerprint: any, postures: any): string {
|
||||||
const canonical = {
|
const canonical = {
|
||||||
username: fp.username ?? null,
|
username: fingerprint.username ?? null,
|
||||||
hostname: fp.hostname ?? null,
|
hostname: fingerprint.hostname ?? null,
|
||||||
platform: fp.platform ?? null,
|
platform: fingerprint.platform ?? null,
|
||||||
osVersion: fp.osVersion ?? null,
|
osVersion: fingerprint.osVersion ?? null,
|
||||||
kernelVersion: fp.kernelVersion ?? null,
|
kernelVersion: fingerprint.kernelVersion ?? null,
|
||||||
arch: fp.arch ?? null,
|
arch: fingerprint.arch ?? null,
|
||||||
deviceModel: fp.deviceModel ?? null,
|
deviceModel: fingerprint.deviceModel ?? null,
|
||||||
serialNumber: fp.serialNumber ?? null,
|
serialNumber: fingerprint.serialNumber ?? null,
|
||||||
platformFingerprint: fp.platformFingerprint ?? null
|
platformFingerprint: fingerprint.platformFingerprint ?? null,
|
||||||
|
|
||||||
|
biometricsEnabled: postures.biometricsEnabled ?? false,
|
||||||
|
diskEncrypted: postures.diskEncrypted ?? false,
|
||||||
|
firewallEnabled: postures.firewallEnabled ?? false,
|
||||||
|
autoUpdatesEnabled: postures.autoUpdatesEnabled ?? false,
|
||||||
|
tpmAvailable: postures.tpmAvailable ?? false,
|
||||||
|
|
||||||
|
windowsDefenderEnabled: postures.windowsDefenderEnabled ?? false,
|
||||||
|
|
||||||
|
macosSipEnabled: postures.macosSipEnabled ?? false,
|
||||||
|
macosGatekeeperEnabled: postures.macosGatekeeperEnabled ?? false,
|
||||||
|
macosFirewallStealthMode: postures.macosFirewallStealthMode ?? false,
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: postures.linuxAppArmorEnabled ?? false,
|
||||||
|
linuxSELinuxEnabled: postures.linuxSELinuxEnabled ?? false
|
||||||
};
|
};
|
||||||
|
|
||||||
return encodeHexLowerCase(
|
return encodeHexLowerCase(
|
||||||
@@ -21,14 +36,23 @@ function fingerprintHash(fp: any): string {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
export async function handleFingerprintInsertion(
|
||||||
if (!fingerprint || !olm.olmId || Object.keys(fingerprint).length < 1) {
|
olm: Olm,
|
||||||
|
fingerprint: any,
|
||||||
|
postures: any
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
!olm?.olmId ||
|
||||||
|
!fingerprint ||
|
||||||
|
!postures ||
|
||||||
|
Object.keys(fingerprint).length === 0 ||
|
||||||
|
Object.keys(postures).length === 0
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hash = fingerprintHash(fingerprint);
|
|
||||||
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
const hash = fingerprintSnapshotHash(fingerprint, postures);
|
||||||
|
|
||||||
const [current] = await db
|
const [current] = await db
|
||||||
.select()
|
.select()
|
||||||
@@ -43,7 +67,9 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
olmId: olm.olmId,
|
olmId: olm.olmId,
|
||||||
firstSeen: now,
|
firstSeen: now,
|
||||||
lastSeen: now,
|
lastSeen: now,
|
||||||
|
lastCollectedAt: now,
|
||||||
|
|
||||||
|
// fingerprint
|
||||||
username: fingerprint.username,
|
username: fingerprint.username,
|
||||||
hostname: fingerprint.hostname,
|
hostname: fingerprint.hostname,
|
||||||
platform: fingerprint.platform,
|
platform: fingerprint.platform,
|
||||||
@@ -52,7 +78,22 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
arch: fingerprint.arch,
|
arch: fingerprint.arch,
|
||||||
deviceModel: fingerprint.deviceModel,
|
deviceModel: fingerprint.deviceModel,
|
||||||
serialNumber: fingerprint.serialNumber,
|
serialNumber: fingerprint.serialNumber,
|
||||||
platformFingerprint: fingerprint.platformFingerprint
|
platformFingerprint: fingerprint.platformFingerprint,
|
||||||
|
|
||||||
|
biometricsEnabled: postures.biometricsEnabled,
|
||||||
|
diskEncrypted: postures.diskEncrypted,
|
||||||
|
firewallEnabled: postures.firewallEnabled,
|
||||||
|
autoUpdatesEnabled: postures.autoUpdatesEnabled,
|
||||||
|
tpmAvailable: postures.tpmAvailable,
|
||||||
|
|
||||||
|
windowsDefenderEnabled: postures.windowsDefenderEnabled,
|
||||||
|
|
||||||
|
macosSipEnabled: postures.macosSipEnabled,
|
||||||
|
macosGatekeeperEnabled: postures.macosGatekeeperEnabled,
|
||||||
|
macosFirewallStealthMode: postures.macosFirewallStealthMode,
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: postures.linuxAppArmorEnabled,
|
||||||
|
linuxSELinuxEnabled: postures.linuxSELinuxEnabled
|
||||||
})
|
})
|
||||||
.returning();
|
.returning();
|
||||||
|
|
||||||
@@ -69,6 +110,21 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
serialNumber: fingerprint.serialNumber,
|
serialNumber: fingerprint.serialNumber,
|
||||||
platformFingerprint: fingerprint.platformFingerprint,
|
platformFingerprint: fingerprint.platformFingerprint,
|
||||||
|
|
||||||
|
biometricsEnabled: postures.biometricsEnabled,
|
||||||
|
diskEncrypted: postures.diskEncrypted,
|
||||||
|
firewallEnabled: postures.firewallEnabled,
|
||||||
|
autoUpdatesEnabled: postures.autoUpdatesEnabled,
|
||||||
|
tpmAvailable: postures.tpmAvailable,
|
||||||
|
|
||||||
|
windowsDefenderEnabled: postures.windowsDefenderEnabled,
|
||||||
|
|
||||||
|
macosSipEnabled: postures.macosSipEnabled,
|
||||||
|
macosGatekeeperEnabled: postures.macosGatekeeperEnabled,
|
||||||
|
macosFirewallStealthMode: postures.macosFirewallStealthMode,
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: postures.linuxAppArmorEnabled,
|
||||||
|
linuxSELinuxEnabled: postures.linuxSELinuxEnabled,
|
||||||
|
|
||||||
hash,
|
hash,
|
||||||
collectedAt: now
|
collectedAt: now
|
||||||
});
|
});
|
||||||
@@ -76,7 +132,6 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get most recent snapshot hash
|
|
||||||
const [latestSnapshot] = await db
|
const [latestSnapshot] = await db
|
||||||
.select({ hash: fingerprintSnapshots.hash })
|
.select({ hash: fingerprintSnapshots.hash })
|
||||||
.from(fingerprintSnapshots)
|
.from(fingerprintSnapshots)
|
||||||
@@ -87,7 +142,6 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
const changed = !latestSnapshot || latestSnapshot.hash !== hash;
|
const changed = !latestSnapshot || latestSnapshot.hash !== hash;
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
// Insert snapshot if it has changed
|
|
||||||
await db.insert(fingerprintSnapshots).values({
|
await db.insert(fingerprintSnapshots).values({
|
||||||
fingerprintId: current.fingerprintId,
|
fingerprintId: current.fingerprintId,
|
||||||
|
|
||||||
@@ -101,15 +155,30 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
serialNumber: fingerprint.serialNumber,
|
serialNumber: fingerprint.serialNumber,
|
||||||
platformFingerprint: fingerprint.platformFingerprint,
|
platformFingerprint: fingerprint.platformFingerprint,
|
||||||
|
|
||||||
|
biometricsEnabled: postures.biometricsEnabled,
|
||||||
|
diskEncrypted: postures.diskEncrypted,
|
||||||
|
firewallEnabled: postures.firewallEnabled,
|
||||||
|
autoUpdatesEnabled: postures.autoUpdatesEnabled,
|
||||||
|
tpmAvailable: postures.tpmAvailable,
|
||||||
|
|
||||||
|
windowsDefenderEnabled: postures.windowsDefenderEnabled,
|
||||||
|
|
||||||
|
macosSipEnabled: postures.macosSipEnabled,
|
||||||
|
macosGatekeeperEnabled: postures.macosGatekeeperEnabled,
|
||||||
|
macosFirewallStealthMode: postures.macosFirewallStealthMode,
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: postures.linuxAppArmorEnabled,
|
||||||
|
linuxSELinuxEnabled: postures.linuxSELinuxEnabled,
|
||||||
|
|
||||||
hash,
|
hash,
|
||||||
collectedAt: now
|
collectedAt: now
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update current fingerprint fully
|
|
||||||
await db
|
await db
|
||||||
.update(currentFingerprint)
|
.update(currentFingerprint)
|
||||||
.set({
|
.set({
|
||||||
lastSeen: now,
|
lastSeen: now,
|
||||||
|
lastCollectedAt: now,
|
||||||
|
|
||||||
username: fingerprint.username,
|
username: fingerprint.username,
|
||||||
hostname: fingerprint.hostname,
|
hostname: fingerprint.hostname,
|
||||||
@@ -119,11 +188,25 @@ export async function handleFingerprintInsertion(olm: Olm, fingerprint: any) {
|
|||||||
arch: fingerprint.arch,
|
arch: fingerprint.arch,
|
||||||
deviceModel: fingerprint.deviceModel,
|
deviceModel: fingerprint.deviceModel,
|
||||||
serialNumber: fingerprint.serialNumber,
|
serialNumber: fingerprint.serialNumber,
|
||||||
platformFingerprint: fingerprint.platformFingerprint
|
platformFingerprint: fingerprint.platformFingerprint,
|
||||||
|
|
||||||
|
biometricsEnabled: postures.biometricsEnabled,
|
||||||
|
diskEncrypted: postures.diskEncrypted,
|
||||||
|
firewallEnabled: postures.firewallEnabled,
|
||||||
|
autoUpdatesEnabled: postures.autoUpdatesEnabled,
|
||||||
|
tpmAvailable: postures.tpmAvailable,
|
||||||
|
|
||||||
|
windowsDefenderEnabled: postures.windowsDefenderEnabled,
|
||||||
|
|
||||||
|
macosSipEnabled: postures.macosSipEnabled,
|
||||||
|
macosGatekeeperEnabled: postures.macosGatekeeperEnabled,
|
||||||
|
macosFirewallStealthMode: postures.macosFirewallStealthMode,
|
||||||
|
|
||||||
|
linuxAppArmorEnabled: postures.linuxAppArmorEnabled,
|
||||||
|
linuxSELinuxEnabled: postures.linuxSELinuxEnabled
|
||||||
})
|
})
|
||||||
.where(eq(currentFingerprint.fingerprintId, current.fingerprintId));
|
.where(eq(currentFingerprint.fingerprintId, current.fingerprintId));
|
||||||
} else {
|
} else {
|
||||||
// No change, so only bump lastSeen
|
|
||||||
await db
|
await db
|
||||||
.update(currentFingerprint)
|
.update(currentFingerprint)
|
||||||
.set({ lastSeen: now })
|
.set({ lastSeen: now })
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { disconnectClient, getClientConfigVersion } from "#dynamic/routers/ws";
|
import { disconnectClient, getClientConfigVersion } from "#dynamic/routers/ws";
|
||||||
import { clientPostureSnapshots, db, currentFingerprint } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { MessageHandler } from "@server/routers/ws";
|
import { MessageHandler } from "@server/routers/ws";
|
||||||
import { clients, olms, Olm } from "@server/db";
|
import { clients, olms, Olm } from "@server/db";
|
||||||
import { eq, lt, isNull, and, or } from "drizzle-orm";
|
import { eq, lt, isNull, and, or } from "drizzle-orm";
|
||||||
@@ -215,36 +215,11 @@ export const handleOlmPingMessage: MessageHandler = async (context) => {
|
|||||||
.set({ archived: false })
|
.set({ archived: false })
|
||||||
.where(eq(olms.olmId, olm.olmId));
|
.where(eq(olms.olmId, olm.olmId));
|
||||||
}
|
}
|
||||||
|
|
||||||
await handleFingerprintInsertion(olm, fingerprint);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Error handling ping message", { error });
|
logger.error("Error handling ping message", { error });
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = Math.floor(Date.now() / 1000);
|
await handleFingerprintInsertion(olm, fingerprint, postures);
|
||||||
|
|
||||||
if (postures && olm.clientId) {
|
|
||||||
await db.insert(clientPostureSnapshots).values({
|
|
||||||
clientId: olm.clientId,
|
|
||||||
|
|
||||||
biometricsEnabled: postures?.biometricsEnabled,
|
|
||||||
diskEncrypted: postures?.diskEncrypted,
|
|
||||||
firewallEnabled: postures?.firewallEnabled,
|
|
||||||
autoUpdatesEnabled: postures?.autoUpdatesEnabled,
|
|
||||||
tpmAvailable: postures?.tpmAvailable,
|
|
||||||
|
|
||||||
windowsDefenderEnabled: postures?.windowsDefenderEnabled,
|
|
||||||
|
|
||||||
macosSipEnabled: postures?.macosSipEnabled,
|
|
||||||
macosGatekeeperEnabled: postures?.macosGatekeeperEnabled,
|
|
||||||
macosFirewallStealthMode: postures?.macosFirewallStealthMode,
|
|
||||||
|
|
||||||
linuxAppArmorEnabled: postures?.linuxAppArmorEnabled,
|
|
||||||
linuxSELinuxEnabled: postures?.linuxSELinuxEnabled,
|
|
||||||
|
|
||||||
collectedAt: now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: {
|
message: {
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { db, orgs } from "@server/db";
|
||||||
clientPostureSnapshots,
|
|
||||||
db,
|
|
||||||
currentFingerprint,
|
|
||||||
orgs
|
|
||||||
} from "@server/db";
|
|
||||||
import { MessageHandler } from "@server/routers/ws";
|
import { MessageHandler } from "@server/routers/ws";
|
||||||
import {
|
import {
|
||||||
clients,
|
clients,
|
||||||
@@ -20,6 +15,7 @@ import { encodeHexLowerCase } from "@oslojs/encoding";
|
|||||||
import { sha256 } from "@oslojs/crypto/sha2";
|
import { sha256 } from "@oslojs/crypto/sha2";
|
||||||
import { buildSiteConfigurationForOlmClient } from "./buildConfiguration";
|
import { buildSiteConfigurationForOlmClient } from "./buildConfiguration";
|
||||||
import { OlmErrorCodes, sendOlmError } from "./error";
|
import { OlmErrorCodes, sendOlmError } from "./error";
|
||||||
|
import { handleFingerprintInsertion } from "./fingerprintingUtils";
|
||||||
|
|
||||||
export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
||||||
logger.info("Handling register olm message!");
|
logger.info("Handling register olm message!");
|
||||||
@@ -50,85 +46,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fingerprint) {
|
await handleFingerprintInsertion(olm, fingerprint, postures);
|
||||||
const [existingFingerprint] = await db
|
|
||||||
.select()
|
|
||||||
.from(currentFingerprint)
|
|
||||||
.where(eq(currentFingerprint.olmId, olm.olmId))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!existingFingerprint) {
|
|
||||||
await db.insert(currentFingerprint).values({
|
|
||||||
olmId: olm.olmId,
|
|
||||||
firstSeen: now,
|
|
||||||
lastSeen: now,
|
|
||||||
|
|
||||||
username: fingerprint.username,
|
|
||||||
hostname: fingerprint.hostname,
|
|
||||||
platform: fingerprint.platform,
|
|
||||||
osVersion: fingerprint.osVersion,
|
|
||||||
kernelVersion: fingerprint.kernelVersion,
|
|
||||||
arch: fingerprint.arch,
|
|
||||||
deviceModel: fingerprint.deviceModel,
|
|
||||||
serialNumber: fingerprint.serialNumber,
|
|
||||||
platformFingerprint: fingerprint.platformFingerprint
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const hasChanges =
|
|
||||||
existingFingerprint.username !== fingerprint.username ||
|
|
||||||
existingFingerprint.hostname !== fingerprint.hostname ||
|
|
||||||
existingFingerprint.platform !== fingerprint.platform ||
|
|
||||||
existingFingerprint.osVersion !== fingerprint.osVersion ||
|
|
||||||
existingFingerprint.kernelVersion !==
|
|
||||||
fingerprint.kernelVersion ||
|
|
||||||
existingFingerprint.arch !== fingerprint.arch ||
|
|
||||||
existingFingerprint.deviceModel !== fingerprint.deviceModel ||
|
|
||||||
existingFingerprint.serialNumber !== fingerprint.serialNumber ||
|
|
||||||
existingFingerprint.platformFingerprint !==
|
|
||||||
fingerprint.platformFingerprint;
|
|
||||||
|
|
||||||
if (hasChanges) {
|
|
||||||
await db
|
|
||||||
.update(currentFingerprint)
|
|
||||||
.set({
|
|
||||||
lastSeen: now,
|
|
||||||
username: fingerprint.username,
|
|
||||||
hostname: fingerprint.hostname,
|
|
||||||
platform: fingerprint.platform,
|
|
||||||
osVersion: fingerprint.osVersion,
|
|
||||||
kernelVersion: fingerprint.kernelVersion,
|
|
||||||
arch: fingerprint.arch,
|
|
||||||
deviceModel: fingerprint.deviceModel,
|
|
||||||
serialNumber: fingerprint.serialNumber,
|
|
||||||
platformFingerprint: fingerprint.platformFingerprint
|
|
||||||
})
|
|
||||||
.where(eq(currentFingerprint.olmId, olm.olmId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postures) {
|
|
||||||
await db.insert(clientPostureSnapshots).values({
|
|
||||||
clientId: olm.clientId,
|
|
||||||
|
|
||||||
biometricsEnabled: postures?.biometricsEnabled,
|
|
||||||
diskEncrypted: postures?.diskEncrypted,
|
|
||||||
firewallEnabled: postures?.firewallEnabled,
|
|
||||||
autoUpdatesEnabled: postures?.autoUpdatesEnabled,
|
|
||||||
tpmAvailable: postures?.tpmAvailable,
|
|
||||||
|
|
||||||
windowsDefenderEnabled: postures?.windowsDefenderEnabled,
|
|
||||||
|
|
||||||
macosSipEnabled: postures?.macosSipEnabled,
|
|
||||||
macosGatekeeperEnabled: postures?.macosGatekeeperEnabled,
|
|
||||||
macosFirewallStealthMode: postures?.macosFirewallStealthMode,
|
|
||||||
|
|
||||||
linuxAppArmorEnabled: postures?.linuxAppArmorEnabled,
|
|
||||||
linuxSELinuxEnabled: postures?.linuxSELinuxEnabled,
|
|
||||||
|
|
||||||
collectedAt: now
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(olmVersion && olm.version !== olmVersion) ||
|
(olmVersion && olm.version !== olmVersion) ||
|
||||||
|
|||||||
Reference in New Issue
Block a user