feat(frontend): c2 tasks panel + history import (sprint 8 phase 2)
- Add getC2Tasks / listCallbackHistory / importC2 API functions + types - useC2Tasks with 2500ms polling (stops when all tasks completed) - useC2CallbackHistory, useImportC2 hooks - C2TaskStatusBadge, C2TasksPanel (expandable output rows, polling indicator) - C2CallbackPicker extracted as shared component (reused in both modals) - ImportC2HistoryModal: 2-step callback picker → paginated history table - SimulationFormPage: RT card + tasks panel share left grid column; Import C2 history button - 37 new tests (api/c2, C2TasksPanel, ImportC2HistoryModal, SimulationFormPage panel visibility) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
import { apiClient } from './client';
|
||||
import type {
|
||||
C2CallbackHistoryResponse,
|
||||
C2Config,
|
||||
C2ConfigInput,
|
||||
C2TestResult,
|
||||
C2CallbacksResponse,
|
||||
C2ExecuteInput,
|
||||
C2ExecuteResponse,
|
||||
C2ImportInput,
|
||||
C2ImportResponse,
|
||||
C2TasksResponse,
|
||||
} from './types';
|
||||
|
||||
export async function getC2Config(engagementId: number): Promise<C2Config | null> {
|
||||
@@ -58,3 +62,33 @@ export async function executeC2(
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getC2Tasks(simulationId: number): Promise<C2TasksResponse> {
|
||||
const { data } = await apiClient.get<C2TasksResponse>(
|
||||
`/simulations/${simulationId}/c2/tasks`,
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function listCallbackHistory(
|
||||
engagementId: number,
|
||||
callbackDisplayId: number,
|
||||
params: { page: number; pageSize: number },
|
||||
): Promise<C2CallbackHistoryResponse> {
|
||||
const { data } = await apiClient.get<C2CallbackHistoryResponse>(
|
||||
`/engagements/${engagementId}/c2/callbacks/${callbackDisplayId}/history`,
|
||||
{ params: { page: params.page, page_size: params.pageSize } },
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function importC2(
|
||||
simulationId: number,
|
||||
input: C2ImportInput,
|
||||
): Promise<C2ImportResponse> {
|
||||
const { data } = await apiClient.post<C2ImportResponse>(
|
||||
`/simulations/${simulationId}/c2/import`,
|
||||
input,
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,8 @@ export interface C2CallbacksResponse {
|
||||
callbacks: C2Callback[];
|
||||
}
|
||||
|
||||
export interface C2Task {
|
||||
// Thin shape returned by the execute endpoint
|
||||
export interface C2ExecuteTask {
|
||||
id: number;
|
||||
mythic_task_display_id: number;
|
||||
command: string;
|
||||
@@ -201,5 +202,52 @@ export interface C2ExecuteInput {
|
||||
}
|
||||
|
||||
export interface C2ExecuteResponse {
|
||||
tasks: C2Task[];
|
||||
tasks: C2ExecuteTask[];
|
||||
}
|
||||
|
||||
// Full shape returned by the tasks list endpoint (M3)
|
||||
export interface C2TaskListItem {
|
||||
id: number;
|
||||
mythic_task_display_id: number;
|
||||
callback_display_id: number;
|
||||
command: string;
|
||||
params: string | null;
|
||||
status: string;
|
||||
completed: boolean;
|
||||
output: string | null;
|
||||
mapping_applied: boolean;
|
||||
created_at: string;
|
||||
completed_at: string | null;
|
||||
}
|
||||
|
||||
export interface C2TasksResponse {
|
||||
tasks: C2TaskListItem[];
|
||||
}
|
||||
|
||||
// Callback history (M4)
|
||||
export interface C2HistoryTask {
|
||||
display_id: number;
|
||||
command: string;
|
||||
status: string;
|
||||
completed: boolean;
|
||||
completed_at: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface C2CallbackHistoryResponse {
|
||||
tasks: C2HistoryTask[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
}
|
||||
|
||||
// Import (M4)
|
||||
export interface C2ImportInput {
|
||||
callback_display_id: number;
|
||||
task_display_ids: number[];
|
||||
}
|
||||
|
||||
export interface C2ImportResponse {
|
||||
imported: number;
|
||||
skipped: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user