mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
feat(fingerprints): receive fingerprints/postures from olm and add to db
This commit is contained in:
@@ -712,6 +712,49 @@ export const clientSiteResourcesAssociationsCache = pgTable(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const clientPostureSnapshots = pgTable("clientPostureSnapshots", {
|
||||||
|
snapshotId: serial("snapshotId").primaryKey(),
|
||||||
|
|
||||||
|
clientId: integer("clientId").references(() => clients.clientId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
|
||||||
|
collectedAt: integer("collectedAt").notNull()
|
||||||
|
});
|
||||||
|
|
||||||
export const olms = pgTable("olms", {
|
export const olms = pgTable("olms", {
|
||||||
olmId: varchar("id").primaryKey(),
|
olmId: varchar("id").primaryKey(),
|
||||||
secretHash: varchar("secretHash").notNull(),
|
secretHash: varchar("secretHash").notNull(),
|
||||||
@@ -730,6 +773,26 @@ export const olms = pgTable("olms", {
|
|||||||
archived: boolean("archived").notNull().default(false)
|
archived: boolean("archived").notNull().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fingerprints = pgTable("fingerprints", {
|
||||||
|
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"), // macos | windows | linux | ios | android | unknown
|
||||||
|
osVersion: text("osVersion"),
|
||||||
|
kernelVersion: text("kernelVersion"),
|
||||||
|
arch: text("arch"),
|
||||||
|
deviceModel: text("deviceModel"),
|
||||||
|
serialNumber: text("serialNumber")
|
||||||
|
});
|
||||||
|
|
||||||
export const olmSessions = pgTable("clientSession", {
|
export const olmSessions = pgTable("clientSession", {
|
||||||
sessionId: varchar("id").primaryKey(),
|
sessionId: varchar("id").primaryKey(),
|
||||||
olmId: varchar("olmId")
|
olmId: varchar("olmId")
|
||||||
|
|||||||
@@ -255,7 +255,9 @@ export const siteResources = sqliteTable("siteResources", {
|
|||||||
aliasAddress: text("aliasAddress"),
|
aliasAddress: text("aliasAddress"),
|
||||||
tcpPortRangeString: text("tcpPortRangeString").notNull().default("*"),
|
tcpPortRangeString: text("tcpPortRangeString").notNull().default("*"),
|
||||||
udpPortRangeString: text("udpPortRangeString").notNull().default("*"),
|
udpPortRangeString: text("udpPortRangeString").notNull().default("*"),
|
||||||
disableIcmp: integer("disableIcmp", { mode: "boolean" }).notNull().default(false)
|
disableIcmp: integer("disableIcmp", { mode: "boolean" })
|
||||||
|
.notNull()
|
||||||
|
.default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const clientSiteResources = sqliteTable("clientSiteResources", {
|
export const clientSiteResources = sqliteTable("clientSiteResources", {
|
||||||
@@ -409,6 +411,69 @@ export const clientSiteResourcesAssociationsCache = sqliteTable(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const clientPostureSnapshots = sqliteTable("clientPostureSnapshots", {
|
||||||
|
snapshotId: integer("snapshotId").primaryKey({ autoIncrement: true }),
|
||||||
|
|
||||||
|
clientId: integer("clientId").references(() => clients.clientId, {
|
||||||
|
onDelete: "cascade"
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
|
||||||
|
collectedAt: integer("collectedAt").notNull()
|
||||||
|
});
|
||||||
|
|
||||||
export const olms = sqliteTable("olms", {
|
export const olms = sqliteTable("olms", {
|
||||||
olmId: text("id").primaryKey(),
|
olmId: text("id").primaryKey(),
|
||||||
secretHash: text("secretHash").notNull(),
|
secretHash: text("secretHash").notNull(),
|
||||||
@@ -427,6 +492,26 @@ export const olms = sqliteTable("olms", {
|
|||||||
archived: integer("archived", { mode: "boolean" }).notNull().default(false)
|
archived: integer("archived", { mode: "boolean" }).notNull().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fingerprints = sqliteTable("fingerprints", {
|
||||||
|
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"), // macos | windows | linux | ios | android | unknown
|
||||||
|
osVersion: text("osVersion"),
|
||||||
|
kernelVersion: text("kernelVersion"),
|
||||||
|
arch: text("arch"),
|
||||||
|
deviceModel: text("deviceModel"),
|
||||||
|
serialNumber: text("serialNumber")
|
||||||
|
});
|
||||||
|
|
||||||
export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", {
|
export const twoFactorBackupCodes = sqliteTable("twoFactorBackupCodes", {
|
||||||
codeId: integer("id").primaryKey({ autoIncrement: true }),
|
codeId: integer("id").primaryKey({ autoIncrement: true }),
|
||||||
userId: text("userId")
|
userId: text("userId")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { db } from "@server/db";
|
import { clientPostureSnapshots, db, fingerprints } from "@server/db";
|
||||||
import { disconnectClient } from "#dynamic/routers/ws";
|
import { disconnectClient } from "#dynamic/routers/ws";
|
||||||
import { MessageHandler } from "@server/routers/ws";
|
import { MessageHandler } from "@server/routers/ws";
|
||||||
import { clients, Olm } from "@server/db";
|
import { clients, Olm } from "@server/db";
|
||||||
@@ -101,7 +101,7 @@ export const handleOlmPingMessage: MessageHandler = async (context) => {
|
|||||||
const { message, client: c, sendToClient } = context;
|
const { message, client: c, sendToClient } = context;
|
||||||
const olm = c as Olm;
|
const olm = c as Olm;
|
||||||
|
|
||||||
const { userToken } = message.data;
|
const { userToken, fingerprint, postures } = message.data;
|
||||||
|
|
||||||
if (!olm) {
|
if (!olm) {
|
||||||
logger.warn("Olm not found");
|
logger.warn("Olm not found");
|
||||||
@@ -174,6 +174,72 @@ export const handleOlmPingMessage: MessageHandler = async (context) => {
|
|||||||
logger.error("Error handling ping message", { error });
|
logger.error("Error handling ping message", { error });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
|
||||||
|
if (fingerprint && olm.olmId) {
|
||||||
|
const [existingFingerprint] = await db
|
||||||
|
.select()
|
||||||
|
.from(fingerprints)
|
||||||
|
.where(eq(fingerprints.olmId, olm.olmId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!existingFingerprint) {
|
||||||
|
await db.insert(fingerprints).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
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await db
|
||||||
|
.update(fingerprints)
|
||||||
|
.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
|
||||||
|
})
|
||||||
|
.where(eq(fingerprints.olmId, olm.olmId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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: {
|
||||||
type: "pong",
|
type: "pong",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
|
clientPostureSnapshots,
|
||||||
clientSiteResourcesAssociationsCache,
|
clientSiteResourcesAssociationsCache,
|
||||||
db,
|
db,
|
||||||
|
fingerprints,
|
||||||
orgs,
|
orgs,
|
||||||
siteResources
|
siteResources
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
@@ -36,8 +38,16 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { publicKey, relay, olmVersion, olmAgent, orgId, userToken } =
|
const {
|
||||||
message.data;
|
publicKey,
|
||||||
|
relay,
|
||||||
|
olmVersion,
|
||||||
|
olmAgent,
|
||||||
|
orgId,
|
||||||
|
userToken,
|
||||||
|
fingerprint,
|
||||||
|
postures
|
||||||
|
} = message.data;
|
||||||
|
|
||||||
if (!olm.clientId) {
|
if (!olm.clientId) {
|
||||||
logger.warn("Olm client ID not found");
|
logger.warn("Olm client ID not found");
|
||||||
@@ -289,6 +299,70 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fingerprint) {
|
||||||
|
const [existingFingerprint] = await db
|
||||||
|
.select()
|
||||||
|
.from(fingerprints)
|
||||||
|
.where(eq(fingerprints.olmId, olm.olmId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!existingFingerprint) {
|
||||||
|
await db.insert(fingerprints).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
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await db
|
||||||
|
.update(fingerprints)
|
||||||
|
.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
|
||||||
|
})
|
||||||
|
.where(eq(fingerprints.olmId, olm.olmId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// REMOVED THIS SO IT CREATES THE INTERFACE AND JUST WAITS FOR THE SITES
|
// REMOVED THIS SO IT CREATES THE INTERFACE AND JUST WAITS FOR THE SITES
|
||||||
// if (siteConfigurations.length === 0) {
|
// if (siteConfigurations.length === 0) {
|
||||||
// logger.warn("No valid site configurations found");
|
// logger.warn("No valid site configurations found");
|
||||||
|
|||||||
Reference in New Issue
Block a user