Implemented multi-select functionality and basic context-menu for session table.

This commit is contained in:
Jakob Friedl
2025-09-09 22:55:43 +02:00
parent 2320b705d3
commit 5f131ae916
3 changed files with 136 additions and 56 deletions

View File

@@ -1,6 +1,6 @@
[Window][Dockspace]
Pos=0,0
Size=1908,999
Size=2548,1359
Collapsed=0
[Window][Debug##Default]
@@ -9,26 +9,26 @@ Size=449,261
Collapsed=0
[Window][Dear ImGui Demo]
Pos=10,43
Size=1453,946
Pos=1852,43
Size=686,653
Collapsed=0
DockId=0x00000001,1
DockId=0x00000007,0
[Window][Agents [Table View]]
Pos=10,43
Size=1187,946
Collapsed=0
DockId=0x00000001,0
DockId=0x00000006,0
[Window][Agents [Graph View]]
Pos=10,43
Size=1888,473
Collapsed=0
DockId=0x00000001,1
DockId=0x00000006,1
[Window][Eventlog]
Pos=1465,43
Size=433,946
Pos=10,698
Size=2528,651
Collapsed=0
DockId=0x00000004,0
@@ -48,9 +48,10 @@ Size=1150,550
Collapsed=0
[Window][Dear ImGui Debug Log]
Pos=60,60
Size=1088,486
Pos=10,698
Size=2528,651
Collapsed=0
DockId=0x00000004,1
[Window][Dear ImGui Metrics/Debugger]
Pos=60,60
@@ -59,9 +60,9 @@ Collapsed=0
[Window][Sessions [Table View]]
Pos=10,43
Size=1453,946
Size=1840,653
Collapsed=0
DockId=0x00000001,0
DockId=0x00000006,0
[Window][Dear ImGui Demo/ResizableChild_478B81A3]
IsChild=1
@@ -93,6 +94,10 @@ Size=1453,471
Collapsed=0
DockId=0x00000002,0
[Window][Dear ImGui Demo/##Basket_87771727]
IsChild=1
Size=614,540
[Table][0xB6880529,2]
RefScale=27
Column 0 Sort=0v
@@ -100,21 +105,21 @@ Column 0 Sort=0v
[Table][0x951FCC8A,6]
RefScale=27
Column 0 Width=48
Column 1 Width=72 Sort=0v
Column 1 Width=112 Sort=0v
Column 2 Width=108
Column 3 Weight=0.5480
Column 3 Width=136
Column 4 Weight=1.0000
Column 5 Weight=-1.0000
Column 5 Width=-1
[Table][0x32886A44,8]
Column 0 Weight=0.7758
Column 1 Weight=1.1556
Column 2 Weight=0.7758
Column 3 Weight=0.9616
Column 4 Weight=0.9616
Column 5 Weight=1.1556
Column 6 Weight=0.3879
Column 7 Weight=1.8263
Column 0 Weight=0.7126
Column 1 Weight=1.0615
Column 2 Weight=0.7126
Column 3 Weight=1.2397
Column 4 Weight=1.6776
Column 5 Weight=1.2397
Column 6 Weight=0.3563
Column 7 Weight=1.5466
[Table][0x51D6F5EA,3]
Column 0 Weight=1.0000
@@ -168,9 +173,9 @@ Column 1 Weight=1.0000
[Table][0xAED4F161,3]
RefScale=27
Column 0 Width=191 Visible=1
Column 1 Width=108 Visible=1 Sort=0v
Column 2 Width=-1 Visible=0
Column 0 Weight=1.0000
Column 1 Width=839 Sort=0v
Column 2 Width=-1
[Table][0x3A20F3F3,3]
RefScale=27
@@ -182,7 +187,7 @@ Column 2 Width=96
[Table][0x302651AD,14]
RefScale=27
Column 0 Width=96 Sort=0v
Column 0 Width=96
Column 1 Width=33
Column 2 Width=33
Column 3 Width=33
@@ -222,13 +227,13 @@ Column 2 Weight=1.0000
[Table][0x127BEAD2,7]
RefScale=27
Column 0 Width=84
Column 1 Width=167
Column 2 Width=191
Column 3 Width=191
Column 4 Width=191
Column 5 Width=191
Column 6 Width=191
Column 0 Width=155
Column 1 Width=155
Column 2 Width=155
Column 3 Width=156
Column 4 Width=156
Column 5 Width=156
Column 6 Width=474
[Table][0x755BE644,3]
RefScale=27
@@ -237,9 +242,10 @@ Column 1 Width=83
Column 2 Width=84
[Table][0xBE0D9DE1,3]
Column 0 Weight=1.0000
Column 1 Weight=1.0000
Column 2 Weight=1.0000
RefScale=27
Column 0 Width=84
Column 1 Width=84
Column 2 Width=217
[Table][0xDE11CCC7,8]
Column 0 Weight=0.7758
@@ -251,10 +257,18 @@ Column 5 Weight=1.1556
Column 6 Weight=0.3879
Column 7 Weight=1.8263
[Docking][Data]
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=1888,946 Split=X
DockNode ID=0x00000003 Parent=0x85940918 SizeRef=1453,473 Split=Y Selected=0x61E02D75
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1453,473 CentralNode=1 Selected=0x61E02D75
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1453,471 Selected=0x6D7E7D39
DockNode ID=0x00000004 Parent=0x85940918 SizeRef=433,473 Selected=0x0FA43D88
[Table][0x61294EC1,3]
RefScale=27
Column 0 Width=119
Column 1 Width=119
Column 2 Width=119
[Docking][Data]
DockSpace ID=0x85940918 Window=0x260A4489 Pos=10,43 Size=2528,1306 Split=Y
DockNode ID=0x00000001 Parent=0x85940918 SizeRef=1453,473 Split=Y Selected=0x61E02D75
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=2528,653 Split=X Selected=0x61E02D75
DockNode ID=0x00000006 Parent=0x00000003 SizeRef=1840,653 CentralNode=1 Selected=0x61E02D75
DockNode ID=0x00000007 Parent=0x00000003 SizeRef=686,653 Selected=0x5E5F7166
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=2528,651 Selected=0x0FA43D88
DockNode ID=0x00000002 Parent=0x85940918 SizeRef=1453,471 Selected=0x6D7E7D39

View File

@@ -19,6 +19,15 @@ proc main() =
views["Listeners"] = addr showListeners
views["Eventlog"] = addr showEventlog
# Create components
var
dockspace = Dockspace()
sessionsTable = SessionsTable("Sessions [Table View]")
sessionsGraph = SessionsTable("Sessions [Graph View]")
listenersTable = ListenersTable("Listeners")
eventlog = Eventlog("Eventlog")
let io = igGetIO()
# main loop
@@ -30,13 +39,11 @@ proc main() =
continue
newFrame()
# UI components/views
Dockspace().draw(addr showConquest, views)
if showSessionsTable: SessionsTable("Sessions [Table View]").draw(addr showSessionsTable)
if showSessionsGraph: SessionsTable("Sessions [Graph View]").draw(addr showSessionsGraph)
if showListeners: ListenersTable("Listeners").draw(addr showListeners)
if showEventlog:Eventlog("Eventlog").draw(addr showEventlog)
# Draw/update UI components/views
dockspace.draw(addr showConquest, views)
if showSessionsTable: sessionsTable.draw(addr showSessionsTable)
if showListeners: listenersTable.draw(addr showListeners)
if showEventlog: eventlog.draw(addr showEventlog)
igShowDemoWindow(nil)

View File

@@ -1,13 +1,13 @@
import times
import imguin/[cimgui, glfw_opengl, simple]
import ../utils/appImGui
import ../../common/[types]
import ../../common/[types, utils]
type
SessionsTableComponent = ref object of RootObj
title: string
agents: seq[Agent]
selection: ptr ImGuiSelectionBasicStorage
let exampleAgents: seq[Agent] = @[
Agent(
@@ -43,6 +43,40 @@ let exampleAgents: seq[Agent] = @[
firstCheckin: now() - initDuration(hours = 1, minutes = 30),
latestCheckin: now() - initDuration(minutes = 5),
sessionKey: [byte 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
),
Agent(
agentId: "C9D8E7F6",
listenerId: "L2468135",
username: "charlie",
hostname: "SERVER-03",
domain: "IT",
ip: "172.16.0.20",
os: "Windows Server 2019",
process: "powershell.exe",
pid: 7890,
elevated: true,
sleep: 30,
tasks: @[],
firstCheckin: now() - initDuration(hours = 3, minutes = 15),
latestCheckin: now() - initDuration(minutes = 10),
sessionKey: [byte 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
),
Agent(
agentId: "G1H2I3J4",
listenerId: "L1357924",
username: "diana",
hostname: "WORKSTATION-04",
domain: "HR",
ip: "192.168.2.15",
os: "Windows 10",
process: "chrome.exe",
pid: 3210,
elevated: false,
sleep: 90,
tasks: @[],
firstCheckin: now() - initDuration(hours = 4),
latestCheckin: now() - initDuration(minutes = 2),
sessionKey: [byte 5, 4, 3, 2, 1, 0, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6]
)
]
@@ -50,6 +84,7 @@ proc SessionsTable*(title: string): SessionsTableComponent =
result = new SessionsTableComponent
result.title = title
result.agents = exampleAgents
result.selection = ImGuiSelectionBasicStorage_ImGuiSelectionBasicStorage()
proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
igSetNextWindowSize(vec2(800, 600), ImGuiCond_Once.int32)
@@ -62,13 +97,12 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
ImGuiTableFlags_Reorderable.int32 or
ImGuiTableFlags_Hideable.int32 or
ImGuiTableFlags_HighlightHoveredColumn.int32 or
ImGuiTableFlags_ContextMenuInBody.int32 or
ImGuiTableFlags_RowBg.int32 or
ImGuiTableFlags_BordersV.int32 or
ImGuiTableFlags_BordersH.int32 or
ImGuiTableFlags_ScrollY.int32 or
ImGuiTableFlags_ScrollX.int32 or
ImGuiTableFlags_NoBordersInBodyUntilResize.int32 or
ImGuiTableFlags_NoBordersInBodyUntilResize.int32 or
ImGui_TableFlags_SizingStretchProp.int32
)
@@ -86,12 +120,20 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
igTableSetupScrollFreeze(0, 1)
igTableHeadersRow()
var multiSelectIO = igBeginMultiSelect(ImGuiMultiSelectFlags_ClearOnEscape.int32 or ImGuiMultiSelectFlags_BoxSelect1d.int32, component.selection[].Size, int32(component.agents.len()))
ImGuiSelectionBasicStorage_ApplyRequests(component.selection, multiSelectIO)
for row in 0..< component.agents.len():
igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f)
let agent = component.agents[row]
if igTableSetColumnIndex(0):
igText(agent.agentId)
if igTableSetColumnIndex(0):
# Enable multi-select functionality
igSetNextItemSelectionUserData(row)
var isSelected = ImGuiSelectionBasicStorage_Contains(component.selection, cast[ImGuiID](row))
discard igSelectable_Bool(agent.agentId, isSelected, ImGuiSelectableFlags_SpanAllColumns.int32, vec2(0.0f, 0.0f))
if igTableSetColumnIndex(1):
igText(agent.ip)
if igTableSetColumnIndex(2):
@@ -107,6 +149,23 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
if igTableSetColumnIndex(7):
igText(agent.latestCheckin.format("yyyy-MM-dd HH:mm:ss"))
# Handle right-click context menu
# Right-clicking the table header to hide/show columns or reset the layout is only possible when no sessions are selected
if component.selection[].Size > 0 and igBeginPopupContextWindow("TableContextMenu", ImGui_PopupFlags_MouseButtonRight.int32):
if igMenuItem("Interact", "ENTER", false, true):
igCloseCurrentPopup()
if igMenuItem("Remove", "DELETE", false, true):
igCloseCurrentPopup()
igEndPopup()
multiSelectIO = igEndMultiSelect()
ImGuiSelectionBasicStorage_ApplyRequests(component.selection, multiSelectIO)
igEndTable()