fix purgatory for users

This commit is contained in:
KingKDot
2026-04-13 22:45:12 -05:00
parent 30e5d4d67b
commit 1831cc96e2
8 changed files with 219 additions and 42 deletions
+77 -8
View File
@@ -28,7 +28,9 @@ db.run(`
last_seen INTEGER,
online INTEGER,
ping_ms INTEGER,
bookmarked INTEGER NOT NULL DEFAULT 0
bookmarked INTEGER NOT NULL DEFAULT 0,
build_tag TEXT,
built_by_user_id INTEGER
);
`);
try {
@@ -52,6 +54,12 @@ try {
try {
db.run(`ALTER TABLE clients ADD COLUMN bookmarked INTEGER NOT NULL DEFAULT 0`);
} catch {}
try {
db.run(`ALTER TABLE clients ADD COLUMN build_tag TEXT`);
} catch {}
try {
db.run(`ALTER TABLE clients ADD COLUMN built_by_user_id INTEGER`);
} catch {}
try {
db.run(`ALTER TABLE clients ADD COLUMN enrollment_status TEXT NOT NULL DEFAULT 'pending'`);
} catch {}
@@ -100,6 +108,9 @@ db.run(
db.run(
`CREATE INDEX IF NOT EXISTS idx_clients_ping_ms ON clients(ping_ms);`,
);
db.run(
`CREATE INDEX IF NOT EXISTS idx_clients_built_by_user_id ON clients(built_by_user_id);`,
);
try {
db.run(`ALTER TABLE clients ADD COLUMN disconnect_reason TEXT`);
} catch {}
@@ -445,8 +456,8 @@ export function upsertClientRow(
) {
const now = partial.lastSeen ?? Date.now();
db.run(
`INSERT INTO clients (id, hwid, role, ip, host, os, arch, version, user, nickname, custom_tag, custom_tag_note, monitors, country, last_seen, online, ping_ms, enrollment_status, public_key, key_fingerprint, cpu, gpu, ram, is_admin, elevation, permissions)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, 0), ?, ?)
`INSERT INTO clients (id, hwid, role, ip, host, os, arch, version, user, nickname, custom_tag, custom_tag_note, monitors, country, last_seen, online, ping_ms, build_tag, built_by_user_id, enrollment_status, public_key, key_fingerprint, cpu, gpu, ram, is_admin, elevation, permissions)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, 0), ?, ?)
ON CONFLICT(id) DO UPDATE SET
hwid=COALESCE(excluded.hwid, clients.hwid),
role=COALESCE(excluded.role, clients.role),
@@ -464,6 +475,8 @@ export function upsertClientRow(
last_seen=excluded.last_seen,
online=COALESCE(excluded.online, clients.online),
ping_ms=COALESCE(excluded.ping_ms, clients.ping_ms),
build_tag=COALESCE(excluded.build_tag, clients.build_tag),
built_by_user_id=COALESCE(excluded.built_by_user_id, clients.built_by_user_id),
enrollment_status=CASE WHEN excluded.enrollment_status <> 'pending' THEN excluded.enrollment_status ELSE clients.enrollment_status END,
public_key=COALESCE(excluded.public_key, clients.public_key),
key_fingerprint=COALESCE(excluded.key_fingerprint, clients.key_fingerprint),
@@ -491,6 +504,8 @@ export function upsertClientRow(
now,
partial.online ?? 0,
partial.pingMs ?? null,
partial.buildTag ?? null,
partial.builtByUserId ?? null,
partial.enrollmentStatus ?? "pending",
partial.publicKey ?? null,
partial.keyFingerprint ?? null,
@@ -779,6 +794,8 @@ export function listClients(filters: ListFilters): ListResult {
osFilter,
countryFilter,
enrollmentFilter,
builtByUserId,
requireBuildOwner,
allowedClientIds,
deniedClientIds,
} = filters;
@@ -818,6 +835,15 @@ export function listClients(filters: ListFilters): ListResult {
params.push(countryFilter.toUpperCase());
}
if (typeof builtByUserId === "number") {
where.push("built_by_user_id=?");
params.push(builtByUserId);
}
if (requireBuildOwner) {
where.push("built_by_user_id IS NOT NULL");
}
if (Array.isArray(allowedClientIds)) {
if (allowedClientIds.length === 0) {
where.push("1=0");
@@ -871,7 +897,7 @@ export function listClients(filters: ListFilters): ListResult {
const rows = db
.query<any>(
`SELECT id, hwid, role, host, os, arch, version, user, nickname, custom_tag as customTag, custom_tag_note as customTagNote, monitors, country, last_seen as lastSeen, online, ping_ms as pingMs, bookmarked, enrollment_status as enrollmentStatus, public_key as publicKey, key_fingerprint as keyFingerprint, cpu, gpu, ram, is_admin as isAdmin, elevation, permissions, disconnect_reason as disconnectReason, disconnect_detail as disconnectDetail
`SELECT id, hwid, role, host, os, arch, version, user, nickname, custom_tag as customTag, custom_tag_note as customTagNote, monitors, country, last_seen as lastSeen, online, ping_ms as pingMs, bookmarked, build_tag as buildTag, built_by_user_id as builtByUserId, enrollment_status as enrollmentStatus, public_key as publicKey, key_fingerprint as keyFingerprint, cpu, gpu, ram, is_admin as isAdmin, elevation, permissions, disconnect_reason as disconnectReason, disconnect_detail as disconnectDetail
FROM clients
${whereSql}
${orderBy}
@@ -897,6 +923,8 @@ export function listClients(filters: ListFilters): ListResult {
pingMs: c.pingMs ?? null,
online: c.online === 1,
bookmarked: c.bookmarked === 1,
buildTag: c.buildTag || null,
builtByUserId: typeof c.builtByUserId === "number" ? c.builtByUserId : null,
enrollmentStatus: c.enrollmentStatus || "pending",
publicKey: c.publicKey || null,
keyFingerprint: c.keyFingerprint || null,
@@ -1348,6 +1376,8 @@ export function lookupClientByPublicKey(
export function getEnrollmentStats(opts?: {
allowedClientIds?: string[];
deniedClientIds?: string[];
builtByUserId?: number;
requireBuildOwner?: boolean;
}): {
pending: number;
approved: number;
@@ -1356,16 +1386,29 @@ export function getEnrollmentStats(opts?: {
let sql = `SELECT COALESCE(enrollment_status,'pending') as status, COUNT(*) as c FROM clients`;
const params: any[] = [];
const where: string[] = [];
if (opts?.allowedClientIds) {
if (opts.allowedClientIds.length === 0) return { pending: 0, approved: 0, denied: 0 };
const placeholders = opts.allowedClientIds.map(() => "?").join(",");
sql += ` WHERE id IN (${placeholders})`;
where.push(`id IN (${placeholders})`);
params.push(...opts.allowedClientIds);
} else if (opts?.deniedClientIds && opts.deniedClientIds.length > 0) {
}
if (opts?.deniedClientIds && opts.deniedClientIds.length > 0) {
const placeholders = opts.deniedClientIds.map(() => "?").join(",");
sql += ` WHERE id NOT IN (${placeholders})`;
where.push(`id NOT IN (${placeholders})`);
params.push(...opts.deniedClientIds);
}
if (typeof opts?.builtByUserId === "number") {
where.push("built_by_user_id = ?");
params.push(opts.builtByUserId);
}
if (opts?.requireBuildOwner) {
where.push("built_by_user_id IS NOT NULL");
}
if (where.length > 0) {
sql += ` WHERE ${where.join(" AND ")}`;
}
sql += ` GROUP BY enrollment_status`;
@@ -1435,6 +1478,8 @@ export function getAllPushSubscriptions(): PushSubscriptionRecord[] {
export function getPendingClients(opts?: {
allowedClientIds?: string[];
deniedClientIds?: string[];
builtByUserId?: number;
requireBuildOwner?: boolean;
}): {
id: string;
host: string | null;
@@ -1455,11 +1500,19 @@ export function getPendingClients(opts?: {
const placeholders = opts.allowedClientIds.map(() => "?").join(",");
sql += ` AND id IN (${placeholders})`;
params.push(...opts.allowedClientIds);
} else if (opts?.deniedClientIds && opts.deniedClientIds.length > 0) {
}
if (opts?.deniedClientIds && opts.deniedClientIds.length > 0) {
const placeholders = opts.deniedClientIds.map(() => "?").join(",");
sql += ` AND id NOT IN (${placeholders})`;
params.push(...opts.deniedClientIds);
}
if (typeof opts?.builtByUserId === "number") {
sql += ` AND built_by_user_id = ?`;
params.push(opts.builtByUserId);
}
if (opts?.requireBuildOwner) {
sql += ` AND built_by_user_id IS NOT NULL`;
}
sql += ` ORDER BY last_seen DESC`;
@@ -1479,6 +1532,22 @@ export function getPendingClients(opts?: {
}));
}
export function getClientBuildOwnership(
id: string,
): { buildTag: string | null; builtByUserId: number | null } | null {
const row = db
.query<{ build_tag: string | null; built_by_user_id: number | null }>(
`SELECT build_tag, built_by_user_id FROM clients WHERE id=?`,
)
.get(id);
if (!row) return null;
return {
buildTag: row.build_tag ?? null,
builtByUserId:
typeof row.built_by_user_id === "number" ? row.built_by_user_id : null,
};
}
export type AutoDeployTrigger = "on_connect" | "on_first_connect" | "on_connect_once";
export type AutoDeploy = {