| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104 |
- function defaultLogLossStreams() {
- return [
- { name: "log_monitor", query: "full_log:log_monitor OR rule.id:100411", min_count: 1 },
- {
- name: "fortigate",
- query: "full_log:fortigate OR full_log:FGT80F OR full_log:FGT60F OR full_log:FGT40F OR full_log:FGT501E",
- min_count: 1,
- },
- { name: "windows_agent", query: "full_log:windows_agent OR full_log:windows", min_count: 1 },
- ];
- }
- function parseJsonOrThrow(text, label) {
- const raw = (text || "").trim();
- if (!raw) {
- return {};
- }
- try {
- return JSON.parse(raw);
- } catch (_err) {
- throw new Error(`Invalid JSON in ${label}`);
- }
- }
- window.socUi = function socUi() {
- return {
- tabs: [
- { key: "overview", label: "Overview" },
- { key: "systems", label: "Systems" },
- { key: "monitoring", label: "Monitoring" },
- { key: "ioc", label: "IOC" },
- { key: "geoip", label: "GeoIP" },
- { key: "iris", label: "IRIS" },
- { key: "shuffle", label: "Shuffle" },
- { key: "wazuh", label: "Wazuh" },
- { key: "mvp", label: "MVP" },
- { key: "explorer", label: "API Explorer" },
- ],
- activeTab: "overview",
- apiBase: window.location.origin,
- internalApiKey: "dev-internal-key",
- errorMessage: "",
- overview: { health: null, autoSync: null },
- systemsMonitor: {
- data: null,
- loading: false,
- autoRefresh: true,
- paused: false,
- intervalSeconds: 20,
- minutes: 60,
- limit: 20,
- lastRefreshAt: null,
- timerId: null,
- },
- simLogs: {
- runs: null,
- startResult: null,
- selectedRunId: "",
- output: null,
- outputLimit: 200,
- autoRefresh: true,
- intervalSeconds: 3,
- timerId: null,
- form: {
- script: "fortigate",
- target: "all",
- scenario: "all",
- count: 1,
- delay_seconds: 0.3,
- forever: false,
- },
- },
- simWazuh: {
- latest: null,
- limit: 100,
- autoRefresh: true,
- showQuery: false,
- },
- systemsCardMeta: [
- { key: "wazuh", label: "Wazuh" },
- { key: "shuffle", label: "Shuffle" },
- { key: "iris", label: "IRIS" },
- { key: "pagerduty", label: "PagerDuty" },
- ],
- logLoss: { result: null },
- cDetections: { state: null, evaluate: null, history: null },
- ioc: { enrich: null, evaluate: null, history: null, upload: null, analysis: null, fileEval: null },
- geoip: { ip: "8.8.8.8", result: null },
- iris: { create: null, list: null },
- shuffle: { status: null, catalog: null, execute: null },
- wazuh: { status: null, list: null, sync: null },
- mvp: {
- status: null,
- ingest: null,
- evaluate: null,
- policyText: JSON.stringify({ risk_thresholds: { high: 80, medium: 50 } }, null, 2),
- ingestText: JSON.stringify(
- {
- source: "wazuh",
- event_type: "vpn_geo_anomaly",
- event_id: "evt-demo-1",
- timestamp: new Date().toISOString(),
- severity: "high",
- title: "VPN login anomaly",
- description: "User login from unusual country",
- asset: { user: "alice", hostname: "win-dc01" },
- network: { src_ip: "8.8.8.8", country: "US" },
- tags: ["vpn", "geo-anomaly"],
- risk_context: { admin_account: false },
- raw: { full_log: "soc_mvp_test=true" },
- payload: {},
- },
- null,
- 2,
- ),
- iocEvalText: JSON.stringify({ ioc_type: "ip", ioc_value: "8.8.8.8", source_event: { event_id: "evt-demo-1" } }, null, 2),
- vpnEvalText: JSON.stringify(
- {
- user: "alice",
- src_ip: "8.8.8.8",
- country_code: "US",
- success: true,
- event_time: new Date().toISOString(),
- is_admin: false,
- off_hours: true,
- first_seen_country: true,
- event_id: "vpn-demo-1",
- },
- null,
- 2,
- ),
- },
- logLossForm: { minutes: 5, createTicket: false, streams: defaultLogLossStreams() },
- cEvalForm: { minutes: 30, query: "soc_mvp_test=true", selectorsText: "c1,c2,c3", dry_run: true, limit: 200 },
- iocForm: {
- ioc_type: "ip",
- ioc_value: "8.8.8.8",
- providersText: "virustotal,abuseipdb",
- malicious_threshold: 1,
- suspicious_threshold: 3,
- },
- iocFileForm: { file: null, analysis_id: "", poll_timeout_seconds: 30, poll_interval_seconds: 2 },
- irisForm: {
- title: "SOC Demo Ticket",
- description: "Created from SOC Integrator UI",
- case_customer: 1,
- case_soc_id: "soc-prod",
- },
- irisList: { limit: 50, offset: 0 },
- shuffleExec: { workflow_id: "", payloadText: JSON.stringify({ hello: "world" }, null, 2) },
- wazuhList: { limit: 50, offset: 0, q: "" },
- wazuhSync: { minutes: 120, limit: 50, q: "soc_mvp_test=true OR event_type:*" },
- explorer: {
- spec: null,
- endpoints: [],
- selectedKey: "",
- selected: null,
- pathParamsText: "{}",
- queryText: "{}",
- bodyText: "{}",
- result: null,
- },
- tabClass(key) {
- return this.activeTab === key
- ? "bg-sky-600 text-white border-sky-600"
- : "bg-white text-slate-700 hover:bg-slate-50";
- },
- init() {
- this.loadHealth();
- this.loadAutoSync();
- this.loadCState();
- this.loadSystemsMonitor();
- this.loadSimRuns();
- this.startSimLogsAutoRefresh();
- this.startSystemsMonitorAutoRefresh();
- this.loadOpenApiSpec();
- },
- simScriptUsesScenario() {
- return this.simLogs.form.script === "endpoint";
- },
- systemsStatusClass(status) {
- if (status === "ok") {
- return "status-ok";
- }
- if (status === "degraded") {
- return "status-warn";
- }
- return "status-down";
- },
- systemsCards() {
- const root = this.unwrapApiData(this.systemsMonitor.data) || {};
- return root.cards || {};
- },
- systemsCard(key) {
- const cards = this.systemsCards();
- return cards[key] || {};
- },
- systemsRecentRows(key) {
- const recent = this.systemsCard(key).recent;
- if (!Array.isArray(recent)) {
- return [];
- }
- return recent.map((row, index) => this.normalizeTableRow(row, index));
- },
- systemsRecentColumns(key) {
- return this.tableColumns(this.systemsRecentRows(key));
- },
- systemsPipelineRows() {
- const root = this.unwrapApiData(this.systemsMonitor.data) || {};
- const pipeline = root.pipeline || {};
- return Object.entries(pipeline).map(([key, value]) => ({ key, value: this.cellText(value) }));
- },
- systemsSetAutoRefresh(enabled) {
- this.systemsMonitor.autoRefresh = Boolean(enabled);
- this.startSystemsMonitorAutoRefresh();
- },
- systemsTogglePaused() {
- this.systemsMonitor.paused = !this.systemsMonitor.paused;
- },
- systemsSetInterval(seconds) {
- const parsed = Number(seconds || 20);
- this.systemsMonitor.intervalSeconds = parsed > 0 ? parsed : 20;
- this.startSystemsMonitorAutoRefresh();
- },
- stopSystemsMonitorAutoRefresh() {
- if (this.systemsMonitor.timerId) {
- clearInterval(this.systemsMonitor.timerId);
- this.systemsMonitor.timerId = null;
- }
- },
- startSystemsMonitorAutoRefresh() {
- this.stopSystemsMonitorAutoRefresh();
- if (!this.systemsMonitor.autoRefresh) {
- return;
- }
- this.systemsMonitor.timerId = setInterval(() => {
- if (!this.systemsMonitor.paused) {
- this.loadSystemsMonitor();
- }
- }, Math.max(5, Number(this.systemsMonitor.intervalSeconds || 20)) * 1000);
- },
- async loadSystemsMonitor() {
- try {
- if (!this.internalApiKey) {
- return;
- }
- this.systemsMonitor.loading = true;
- const params = new URLSearchParams({
- minutes: String(Math.max(1, Number(this.systemsMonitor.minutes || 60))),
- limit: String(Math.max(1, Number(this.systemsMonitor.limit || 20))),
- });
- this.systemsMonitor.data = await this.apiCall(`/monitor/systems?${params.toString()}`, {
- internal: true,
- });
- this.systemsMonitor.lastRefreshAt = new Date().toISOString();
- } catch (err) {
- this.setErr("Systems monitor failed", err);
- } finally {
- this.systemsMonitor.loading = false;
- }
- },
- async loadSimRuns() {
- try {
- if (!this.internalApiKey) {
- return;
- }
- this.simLogs.runs = await this.apiCall("/sim/logs/runs", { internal: true });
- const rows = this.extractRows(this.simLogs.runs);
- if (!this.simLogs.selectedRunId && rows.length) {
- this.simLogs.selectedRunId = rows[0].run_id || "";
- if (this.simLogs.selectedRunId) {
- await this.loadSimWazuhLatest(this.simLogs.selectedRunId);
- }
- }
- } catch (err) {
- this.setErr("Load sim runs failed", err);
- }
- },
- async startSimRun() {
- try {
- const payload = {
- script: this.simLogs.form.script,
- target: this.simLogs.form.target || "all",
- scenario: this.simLogs.form.scenario || "all",
- count: Number(this.simLogs.form.count || 1),
- delay_seconds: Number(this.simLogs.form.delay_seconds || 0.3),
- forever: Boolean(this.simLogs.form.forever),
- };
- this.simLogs.startResult = await this.apiCall("/sim/logs/start", {
- method: "POST",
- internal: true,
- json: payload,
- });
- await this.loadSimRuns();
- const started = this.unwrapApiData(this.simLogs.startResult)?.run;
- if (started && started.run_id) {
- this.simLogs.selectedRunId = started.run_id;
- await this.loadSimOutput(started.run_id);
- await this.loadSimWazuhLatest(started.run_id);
- }
- } catch (err) {
- this.setErr("Start sim run failed", err);
- }
- },
- async stopSimRun(runId) {
- try {
- await this.apiCall(`/sim/logs/stop/${encodeURIComponent(runId)}`, {
- method: "POST",
- internal: true,
- });
- await this.loadSimRuns();
- if (this.simLogs.selectedRunId === runId) {
- await this.loadSimOutput(runId);
- await this.loadSimWazuhLatest(runId);
- }
- } catch (err) {
- this.setErr("Stop sim run failed", err);
- }
- },
- async stopRunningSimRuns() {
- try {
- await this.apiCall("/sim/logs/stop-running", {
- method: "POST",
- internal: true,
- });
- await this.loadSimRuns();
- if (this.simLogs.selectedRunId) {
- await this.loadSimOutput(this.simLogs.selectedRunId);
- await this.loadSimWazuhLatest(this.simLogs.selectedRunId);
- }
- } catch (err) {
- this.setErr("Stop running sim runs failed", err);
- }
- },
- simRunRows() {
- return this.extractRows(this.simLogs.runs);
- },
- selectSimRun(runId) {
- this.simLogs.selectedRunId = runId || "";
- this.loadSimOutput(this.simLogs.selectedRunId);
- this.loadSimWazuhLatest(this.simLogs.selectedRunId);
- },
- simSelectedRun() {
- const rows = this.simRunRows();
- return rows.find((row) => row.run_id === this.simLogs.selectedRunId) || null;
- },
- stopSimLogsAutoRefresh() {
- if (this.simLogs.timerId) {
- clearInterval(this.simLogs.timerId);
- this.simLogs.timerId = null;
- }
- },
- startSimLogsAutoRefresh() {
- this.stopSimLogsAutoRefresh();
- if (!this.simLogs.autoRefresh) {
- return;
- }
- this.simLogs.timerId = setInterval(async () => {
- if (this.activeTab !== "systems") {
- return;
- }
- try {
- await this.loadSimRuns();
- if (this.simLogs.selectedRunId) {
- await this.loadSimOutput(this.simLogs.selectedRunId);
- await this.loadSimWazuhLatest(this.simLogs.selectedRunId);
- }
- } catch (_err) {
- // per-request error is already handled by each loader
- }
- }, 5000);
- },
- async loadSimOutput(runId = "") {
- const selectedRunId = runId || this.simLogs.selectedRunId;
- if (!selectedRunId) {
- this.simLogs.output = null;
- return;
- }
- try {
- const limit = Math.max(10, Number(this.simLogs.outputLimit || 200));
- this.simLogs.output = await this.apiCall(
- `/sim/logs/output/${encodeURIComponent(selectedRunId)}?limit=${limit}`,
- { internal: true },
- );
- } catch (err) {
- this.setErr("Load sim output failed", err);
- }
- },
- async loadSimWazuhLatest(runId = "") {
- const selectedRunId = runId || this.simLogs.selectedRunId;
- if (!selectedRunId) {
- this.simWazuh.latest = null;
- return;
- }
- try {
- const limit = 100;
- this.simWazuh.latest = await this.apiCall(
- `/sim/logs/wazuh-latest/${encodeURIComponent(selectedRunId)}?limit=${limit}&minutes=1440&include_raw=true`,
- { internal: true },
- );
- } catch (err) {
- this.setErr("Load sim Wazuh latest failed", err);
- }
- },
- simWazuhEventsRows() {
- const root = this.unwrapApiData(this.simWazuh.latest) || {};
- const events = Array.isArray(root.events) ? root.events : [];
- return events.map((row, index) => this.normalizeTableRow(row, index));
- },
- simWazuhRulesRows() {
- const root = this.unwrapApiData(this.simWazuh.latest) || {};
- const rules = Array.isArray(root.rules) ? root.rules : [];
- return rules.map((row, index) => this.normalizeTableRow(row, index));
- },
- simWazuhEventTableRows() {
- return this.simWazuhEventsRows().map((row) => ({
- time: row["@timestamp"] || row.timestamp || "",
- rule_id: row.rule_id || row.rule?.id || "",
- rule_description: row.rule_description || row.rule?.description || "",
- full_log: row.full_log || "",
- }));
- },
- parseFullLog(fullLog) {
- const text = String(fullLog || "").trim();
- if (!text) {
- return {};
- }
- const parsed = {};
- const regex = /([A-Za-z0-9_.-]+)=("([^"]*)"|[^\s]+)/g;
- let match = null;
- while ((match = regex.exec(text)) !== null) {
- const key = match[1];
- let value = match[3] !== undefined ? match[3] : match[2];
- if (value === "true") {
- value = true;
- } else if (value === "false") {
- value = false;
- } else if (/^-?\d+$/.test(value)) {
- value = Number(value);
- } else if (/^-?\d+\.\d+$/.test(value)) {
- value = Number(value);
- }
- parsed[key] = value;
- }
- if (Object.keys(parsed).length === 0) {
- return { message: text };
- }
- return parsed;
- },
- fullLogAsJsonText(fullLog) {
- return JSON.stringify(this.parseFullLog(fullLog), null, 2);
- },
- pretty(value) {
- if (value === null || value === undefined) {
- return "No data yet";
- }
- try {
- return JSON.stringify(value, null, 2);
- } catch (_err) {
- return String(value);
- }
- },
- unwrapApiData(payload) {
- if (payload && typeof payload === "object" && !Array.isArray(payload) && Object.prototype.hasOwnProperty.call(payload, "data")) {
- return payload.data;
- }
- return payload;
- },
- findFirstArray(node, depth = 0) {
- if (depth > 5 || node === null || node === undefined) {
- return null;
- }
- if (Array.isArray(node)) {
- return node;
- }
- if (typeof node !== "object") {
- return null;
- }
- const preferredKeys = ["items", "matches", "results", "alerts", "agents", "workflows", "apps", "rows", "data"];
- for (const key of preferredKeys) {
- if (Array.isArray(node[key])) {
- return node[key];
- }
- }
- for (const value of Object.values(node)) {
- const found = this.findFirstArray(value, depth + 1);
- if (found) {
- return found;
- }
- }
- return null;
- },
- normalizeTableRow(row, index) {
- if (row && typeof row === "object" && !Array.isArray(row)) {
- return row;
- }
- return { row: index + 1, value: row };
- },
- extractRows(payload) {
- const root = this.unwrapApiData(payload);
- const rows = this.findFirstArray(root) || [];
- return rows.map((row, index) => this.normalizeTableRow(row, index));
- },
- tableColumns(rows) {
- const colSet = new Set();
- const sample = rows.slice(0, 30);
- for (const row of sample) {
- if (!row || typeof row !== "object" || Array.isArray(row)) {
- continue;
- }
- for (const key of Object.keys(row)) {
- if (colSet.size >= 10) {
- break;
- }
- colSet.add(key);
- }
- if (colSet.size >= 10) {
- break;
- }
- }
- return Array.from(colSet);
- },
- cellText(value) {
- if (value === null || value === undefined) {
- return "";
- }
- if (typeof value === "string") {
- return value;
- }
- if (typeof value === "number" || typeof value === "boolean") {
- return String(value);
- }
- return JSON.stringify(value);
- },
- keyValueRows(payload) {
- const root = this.unwrapApiData(payload);
- if (!root || typeof root !== "object" || Array.isArray(root)) {
- return [];
- }
- return Object.entries(root).map(([key, value]) => ({
- key,
- value: this.cellText(value),
- }));
- },
- providersList() {
- return (this.iocForm.providersText || "")
- .split(",")
- .map((s) => s.trim().toLowerCase())
- .filter((s) => s.length > 0);
- },
- internalHeaders() {
- return this.internalApiKey ? { "x-internal-api-key": this.internalApiKey } : {};
- },
- async apiCall(path, options = {}) {
- this.errorMessage = "";
- const headers = {
- Accept: "application/json",
- ...(options.json ? { "Content-Type": "application/json" } : {}),
- ...(options.internal ? this.internalHeaders() : {}),
- ...(options.headers || {}),
- };
- const response = await fetch(`${this.apiBase}${path}`, {
- method: options.method || "GET",
- headers,
- body: options.json ? JSON.stringify(options.json) : options.body,
- });
- let data = null;
- try {
- data = await response.json();
- } catch (_err) {
- data = { detail: "Non-JSON response", status: response.status };
- }
- if (!response.ok) {
- const detail = data && data.detail ? data.detail : `HTTP ${response.status}`;
- throw new Error(detail);
- }
- return data;
- },
- setErr(prefix, err) {
- this.errorMessage = `${prefix}: ${err.message}`;
- },
- async loadHealth() {
- try {
- this.overview.health = await this.apiCall("/health");
- } catch (err) {
- this.setErr("Health failed", err);
- }
- },
- async loadAutoSync() {
- try {
- this.overview.autoSync = await this.apiCall("/wazuh/auto-sync/status");
- } catch (err) {
- this.setErr("Auto-sync failed", err);
- }
- },
- applyLogLossPreset(preset) {
- if (preset === "b2") {
- this.logLossForm.minutes = 10;
- this.logLossForm.streams = [{ name: "b2_log_monitor", query: "full_log:log_monitor OR rule.id:100411", min_count: 1 }];
- } else {
- this.logLossForm.minutes = 5;
- this.logLossForm.streams = defaultLogLossStreams();
- }
- },
- addLogLossStream() {
- this.logLossForm.streams.push({ name: "", query: "", min_count: 1 });
- },
- removeLogLossStream(index) {
- this.logLossForm.streams.splice(index, 1);
- },
- async runLogLossCheck() {
- try {
- this.logLoss.result = await this.apiCall(
- `/monitor/log-loss/check?create_ticket=${this.logLossForm.createTicket ? "true" : "false"}`,
- {
- method: "POST",
- internal: true,
- json: {
- minutes: Number(this.logLossForm.minutes || 5),
- streams: this.logLossForm.streams.map((s) => ({
- name: s.name,
- query: s.query,
- min_count: Number(s.min_count || 0),
- })),
- },
- },
- );
- } catch (err) {
- this.setErr("Log-loss check failed", err);
- }
- },
- async loadCState() {
- try {
- this.cDetections.state = await this.apiCall("/monitor/c-detections/state", { internal: true });
- } catch (err) {
- this.setErr("C state failed", err);
- }
- },
- async runCEvaluate() {
- try {
- const selectors = this.cEvalForm.selectorsText
- .split(",")
- .map((x) => x.trim())
- .filter((x) => x.length > 0);
- this.cDetections.evaluate = await this.apiCall("/monitor/c-detections/evaluate", {
- method: "POST",
- internal: true,
- json: {
- minutes: Number(this.cEvalForm.minutes || 30),
- query: this.cEvalForm.query,
- selectors,
- dry_run: Boolean(this.cEvalForm.dry_run),
- limit: Number(this.cEvalForm.limit || 200),
- },
- });
- } catch (err) {
- this.setErr("C evaluate failed", err);
- }
- },
- async loadCHistory() {
- try {
- this.cDetections.history = await this.apiCall("/monitor/c-detections/history?limit=50&offset=0", { internal: true });
- } catch (err) {
- this.setErr("C history failed", err);
- }
- },
- async runIocEnrich() {
- try {
- this.ioc.enrich = await this.apiCall("/ioc/enrich", {
- method: "POST",
- json: {
- ioc_type: this.iocForm.ioc_type,
- ioc_value: this.iocForm.ioc_value,
- providers: this.providersList(),
- },
- });
- } catch (err) {
- this.setErr("IOC enrich failed", err);
- }
- },
- async runIocEvaluate() {
- try {
- this.ioc.evaluate = await this.apiCall("/ioc/evaluate", {
- method: "POST",
- json: {
- ioc_type: this.iocForm.ioc_type,
- ioc_value: this.iocForm.ioc_value,
- providers: this.providersList(),
- malicious_threshold: Number(this.iocForm.malicious_threshold || 1),
- suspicious_threshold: Number(this.iocForm.suspicious_threshold || 3),
- },
- });
- } catch (err) {
- this.setErr("IOC evaluate failed", err);
- }
- },
- async loadIocHistory() {
- try {
- this.ioc.history = await this.apiCall("/ioc/history?limit=50&offset=0");
- } catch (err) {
- this.setErr("IOC history failed", err);
- }
- },
- async lookupGeoIp() {
- try {
- const ip = String(this.geoip.ip || "").trim();
- if (!ip) {
- throw new Error("IP is required");
- }
- this.geoip.result = await this.apiCall(`/geoip/${encodeURIComponent(ip)}`);
- } catch (err) {
- this.setErr("GeoIP lookup failed", err);
- }
- },
- onFileSelected(event) {
- const files = event && event.target ? event.target.files : null;
- this.iocFileForm.file = files && files.length ? files[0] : null;
- },
- async uploadIocFile() {
- try {
- if (!this.iocFileForm.file) {
- throw new Error("Select a file first");
- }
- const form = new FormData();
- form.append("file", this.iocFileForm.file);
- this.ioc.upload = await this.apiCall("/ioc/upload-file", { method: "POST", body: form });
- } catch (err) {
- this.setErr("IOC upload failed", err);
- }
- },
- async evaluateIocFile() {
- try {
- if (!this.iocFileForm.file) {
- throw new Error("Select a file first");
- }
- const params = new URLSearchParams({
- malicious_threshold: String(this.iocForm.malicious_threshold || 1),
- suspicious_threshold: String(this.iocForm.suspicious_threshold || 3),
- poll_timeout_seconds: String(this.iocFileForm.poll_timeout_seconds || 30),
- poll_interval_seconds: String(this.iocFileForm.poll_interval_seconds || 2),
- });
- const form = new FormData();
- form.append("file", this.iocFileForm.file);
- this.ioc.fileEval = await this.apiCall(`/ioc/evaluate-file?${params.toString()}`, { method: "POST", body: form });
- } catch (err) {
- this.setErr("IOC file evaluate failed", err);
- }
- },
- async getIocAnalysis() {
- try {
- if (!this.iocFileForm.analysis_id.trim()) {
- throw new Error("analysis_id is required");
- }
- this.ioc.analysis = await this.apiCall(`/ioc/analysis/${encodeURIComponent(this.iocFileForm.analysis_id.trim())}`);
- } catch (err) {
- this.setErr("IOC analysis failed", err);
- }
- },
- async createIrisTicket() {
- try {
- this.iris.create = await this.apiCall("/iris/tickets", {
- method: "POST",
- json: {
- title: this.irisForm.title,
- description: this.irisForm.description,
- case_customer: Number(this.irisForm.case_customer || 1),
- case_soc_id: this.irisForm.case_soc_id,
- payload: {},
- },
- });
- } catch (err) {
- this.setErr("IRIS create failed", err);
- }
- },
- async loadIrisTickets() {
- try {
- this.iris.list = await this.apiCall(`/iris/tickets?limit=${Number(this.irisList.limit || 50)}&offset=${Number(this.irisList.offset || 0)}`);
- } catch (err) {
- this.setErr("IRIS list failed", err);
- }
- },
- async loadShuffleHealth() {
- try {
- this.shuffle.status = await this.apiCall("/shuffle/health");
- } catch (err) {
- this.setErr("Shuffle health failed", err);
- }
- },
- async loadShuffleAuth() {
- try {
- this.shuffle.status = await this.apiCall("/shuffle/auth-test");
- } catch (err) {
- this.setErr("Shuffle auth failed", err);
- }
- },
- async loadShuffleApps() {
- try {
- this.shuffle.catalog = await this.apiCall("/shuffle/apps");
- } catch (err) {
- this.setErr("Shuffle apps failed", err);
- }
- },
- async loadShuffleWorkflows() {
- try {
- this.shuffle.catalog = await this.apiCall("/shuffle/workflows");
- } catch (err) {
- this.setErr("Shuffle workflows failed", err);
- }
- },
- async executeShuffleWorkflow() {
- try {
- if (!this.shuffleExec.workflow_id.trim()) {
- throw new Error("workflow_id is required");
- }
- const payload = parseJsonOrThrow(this.shuffleExec.payloadText, "shuffle payload");
- this.shuffle.execute = await this.apiCall(`/shuffle/workflows/${encodeURIComponent(this.shuffleExec.workflow_id.trim())}/execute`, {
- method: "POST",
- json: payload,
- });
- } catch (err) {
- this.setErr("Shuffle execute failed", err);
- }
- },
- async wazuhCall(mode) {
- try {
- if (mode === "auth") {
- this.wazuh.status = await this.apiCall("/wazuh/auth-test");
- } else if (mode === "manager") {
- this.wazuh.status = await this.apiCall("/wazuh/manager-info");
- } else if (mode === "version") {
- this.wazuh.status = await this.apiCall("/sync/wazuh-version");
- } else if (mode === "autosync") {
- this.wazuh.status = await this.apiCall("/wazuh/auto-sync/status");
- }
- } catch (err) {
- this.setErr("Wazuh status failed", err);
- }
- },
- async loadWazuhAgents() {
- try {
- this.wazuh.list = await this.apiCall(`/wazuh/agents?limit=${Number(this.wazuhList.limit || 50)}&offset=${Number(this.wazuhList.offset || 0)}`);
- } catch (err) {
- this.setErr("Wazuh agents failed", err);
- }
- },
- async loadWazuhAlerts() {
- try {
- const q = this.wazuhList.q ? `&q=${encodeURIComponent(this.wazuhList.q)}` : "";
- this.wazuh.list = await this.apiCall(`/wazuh/alerts?limit=${Number(this.wazuhList.limit || 50)}&offset=${Number(this.wazuhList.offset || 0)}${q}`);
- } catch (err) {
- this.setErr("Wazuh alerts failed", err);
- }
- },
- async loadWazuhManagerLogs() {
- try {
- const q = this.wazuhList.q ? `&q=${encodeURIComponent(this.wazuhList.q)}` : "";
- this.wazuh.list = await this.apiCall(`/wazuh/manager-logs?limit=${Number(this.wazuhList.limit || 50)}&offset=${Number(this.wazuhList.offset || 0)}${q}`);
- } catch (err) {
- this.setErr("Wazuh manager logs failed", err);
- }
- },
- async syncWazuhToMvp() {
- try {
- const params = new URLSearchParams({
- limit: String(Number(this.wazuhSync.limit || 50)),
- minutes: String(Number(this.wazuhSync.minutes || 120)),
- q: String(this.wazuhSync.q || "soc_mvp_test=true OR event_type:*"),
- });
- this.wazuh.sync = await this.apiCall(`/wazuh/sync-to-mvp?${params.toString()}`, {
- method: "POST",
- internal: true,
- });
- } catch (err) {
- this.setErr("Wazuh sync failed", err);
- }
- },
- async loadMvpDependencies() {
- try {
- this.mvp.status = await this.apiCall("/mvp/health/dependencies");
- } catch (err) {
- this.setErr("MVP dependencies failed", err);
- }
- },
- async loadMvpPolicy() {
- try {
- const result = await this.apiCall("/mvp/config/policies");
- this.mvp.status = result;
- const policy = result && result.data ? result.data.policy : null;
- if (policy) {
- this.mvp.policyText = JSON.stringify(policy, null, 2);
- }
- } catch (err) {
- this.setErr("MVP policy get failed", err);
- }
- },
- async updateMvpPolicy() {
- try {
- const payload = parseJsonOrThrow(this.mvp.policyText, "policy JSON");
- this.mvp.status = await this.apiCall("/mvp/config/policies", {
- method: "PUT",
- internal: true,
- json: payload,
- });
- } catch (err) {
- this.setErr("MVP policy update failed", err);
- }
- },
- async mvpIngestIncident() {
- try {
- const payload = parseJsonOrThrow(this.mvp.ingestText, "mvp ingest JSON");
- this.mvp.ingest = await this.apiCall("/mvp/incidents/ingest", {
- method: "POST",
- internal: true,
- json: payload,
- });
- } catch (err) {
- this.setErr("MVP ingest failed", err);
- }
- },
- async mvpEvaluateIoc() {
- try {
- const payload = parseJsonOrThrow(this.mvp.iocEvalText, "mvp IOC JSON");
- this.mvp.evaluate = await this.apiCall("/mvp/ioc/evaluate", {
- method: "POST",
- internal: true,
- json: payload,
- });
- } catch (err) {
- this.setErr("MVP IOC evaluate failed", err);
- }
- },
- async mvpEvaluateVpn() {
- try {
- const payload = parseJsonOrThrow(this.mvp.vpnEvalText, "mvp VPN JSON");
- this.mvp.evaluate = await this.apiCall("/mvp/vpn/evaluate", {
- method: "POST",
- internal: true,
- json: payload,
- });
- } catch (err) {
- this.setErr("MVP VPN evaluate failed", err);
- }
- },
- async loadOpenApiSpec() {
- try {
- const spec = await this.apiCall("/openapi.json");
- this.explorer.spec = spec;
- const endpoints = [];
- const paths = spec && spec.paths ? spec.paths : {};
- Object.keys(paths).forEach((path) => {
- const item = paths[path] || {};
- ["get", "post", "put", "delete", "patch"].forEach((method) => {
- if (item[method]) {
- endpoints.push({
- key: `${method.toUpperCase()} ${path}`,
- method,
- path,
- operation: item[method],
- pathItem: item,
- });
- }
- });
- });
- this.explorer.endpoints = endpoints.sort((a, b) => a.key.localeCompare(b.key));
- if (this.explorer.endpoints.length > 0 && !this.explorer.selectedKey) {
- this.explorer.selectedKey = this.explorer.endpoints[0].key;
- this.selectExplorerEndpoint();
- }
- } catch (err) {
- this.setErr("OpenAPI load failed", err);
- }
- },
- selectExplorerEndpoint() {
- const selected = this.explorer.endpoints.find((x) => x.key === this.explorer.selectedKey) || null;
- this.explorer.selected = selected;
- if (!selected) {
- return;
- }
- const params = []
- .concat(selected.pathItem.parameters || [])
- .concat(selected.operation.parameters || []);
- const pathParams = {};
- const queryParams = {};
- params.forEach((p) => {
- if (!p || !p.name) {
- return;
- }
- if (p.in === "path") {
- pathParams[p.name] = "";
- }
- if (p.in === "query") {
- queryParams[p.name] = "";
- }
- });
- this.explorer.pathParamsText = JSON.stringify(pathParams, null, 2);
- this.explorer.queryText = JSON.stringify(queryParams, null, 2);
- const hasJsonBody =
- selected.operation &&
- selected.operation.requestBody &&
- selected.operation.requestBody.content &&
- selected.operation.requestBody.content["application/json"];
- this.explorer.bodyText = hasJsonBody ? JSON.stringify({}, null, 2) : "{}";
- },
- async runExplorerRequest() {
- try {
- const selected = this.explorer.selected;
- if (!selected) {
- throw new Error("Select an endpoint first");
- }
- const pathParams = parseJsonOrThrow(this.explorer.pathParamsText, "path params");
- const queryParams = parseJsonOrThrow(this.explorer.queryText, "query params");
- const body = parseJsonOrThrow(this.explorer.bodyText, "body");
- let path = selected.path;
- Object.keys(pathParams).forEach((k) => {
- path = path.replace(`{${k}}`, encodeURIComponent(String(pathParams[k])));
- });
- const qs = new URLSearchParams();
- Object.keys(queryParams).forEach((k) => {
- const v = queryParams[k];
- if (v !== "" && v !== null && v !== undefined) {
- qs.append(k, String(v));
- }
- });
- const fullPath = qs.toString() ? `${path}?${qs.toString()}` : path;
- const needsInternal = fullPath.startsWith("/monitor/") || fullPath.startsWith("/mvp/") || fullPath.startsWith("/wazuh/sync-to-mvp");
- const withBody = ["post", "put", "patch"].includes(selected.method);
- this.explorer.result = await this.apiCall(fullPath, {
- method: selected.method.toUpperCase(),
- internal: needsInternal,
- ...(withBody ? { json: body } : {}),
- });
- } catch (err) {
- this.setErr("Explorer request failed", err);
- }
- },
- };
- };
|