From 71a02f5f96564dc7f6a30b248eb99c0f534dd14a Mon Sep 17 00:00:00 2001 From: James Kerr Date: Wed, 12 Feb 2025 14:19:34 -0800 Subject: [PATCH] Remove brimcap capabilities --- apps/zui/src/core/zq.ts | 2 +- .../loads/handlers/preview-load-files.ts | 23 +--- apps/zui/src/domain/loads/messages.ts | 1 - .../zui/src/domain/loads/operations/create.ts | 1 - .../domain/loads/operations/get-file-types.ts | 16 --- apps/zui/src/domain/loads/operations/index.ts | 1 - apps/zui/src/models/snapshot/source-set.ts | 2 - apps/zui/src/plugins/brimcap/analyze.ts | 27 ---- apps/zui/src/plugins/brimcap/cli.ts | 126 ------------------ apps/zui/src/plugins/brimcap/config.ts | 3 - .../zui/src/plugins/brimcap/configurations.ts | 47 ------- .../plugins/brimcap/configure-zeek-pool.ts | 10 -- apps/zui/src/plugins/brimcap/index.ts | 19 +-- apps/zui/src/plugins/brimcap/loader.ts | 97 -------------- .../src/plugins/brimcap/packets/download.ts | 62 --------- .../src/plugins/brimcap/packets/is-pcap.ts | 29 ---- .../src/plugins/brimcap/packets/menu-item.ts | 44 ------ .../plugins/brimcap/packets/query-conn-log.ts | 10 -- apps/zui/src/plugins/brimcap/packets/types.ts | 2 - apps/zui/src/plugins/brimcap/storage.ts | 25 ---- .../src/plugins/brimcap/suricata/update.ts | 36 ----- .../src/plugins/brimcap/transform-stream.ts | 45 ------- apps/zui/src/views/results-pane/error.tsx | 4 +- .../views/results-pane/errors/empty-query.tsx | 3 + .../errors/missing-pool-error.tsx | 115 ---------------- .../views/results-pane/run-results-query.tsx | 1 + .../tests/no-pool-specified.spec.ts | 35 ----- packages/zui-player/tests/packets.spec.ts | 28 +--- 28 files changed, 17 insertions(+), 797 deletions(-) delete mode 100644 apps/zui/src/domain/loads/operations/get-file-types.ts delete mode 100644 apps/zui/src/plugins/brimcap/analyze.ts delete mode 100644 apps/zui/src/plugins/brimcap/cli.ts delete mode 100644 apps/zui/src/plugins/brimcap/configurations.ts delete mode 100644 apps/zui/src/plugins/brimcap/configure-zeek-pool.ts delete mode 100644 apps/zui/src/plugins/brimcap/loader.ts delete mode 100644 apps/zui/src/plugins/brimcap/packets/download.ts delete mode 100644 apps/zui/src/plugins/brimcap/packets/is-pcap.ts delete mode 100644 apps/zui/src/plugins/brimcap/packets/menu-item.ts delete mode 100644 apps/zui/src/plugins/brimcap/packets/query-conn-log.ts delete mode 100644 apps/zui/src/plugins/brimcap/packets/types.ts delete mode 100644 apps/zui/src/plugins/brimcap/storage.ts delete mode 100644 apps/zui/src/plugins/brimcap/suricata/update.ts delete mode 100644 apps/zui/src/plugins/brimcap/transform-stream.ts create mode 100644 apps/zui/src/views/results-pane/errors/empty-query.tsx delete mode 100644 apps/zui/src/views/results-pane/errors/missing-pool-error.tsx delete mode 100644 packages/zui-player/tests/no-pool-specified.spec.ts diff --git a/apps/zui/src/core/zq.ts b/apps/zui/src/core/zq.ts index 7d52a2e583..e68c1b9d00 100644 --- a/apps/zui/src/core/zq.ts +++ b/apps/zui/src/core/zq.ts @@ -6,5 +6,5 @@ export const zq = ((opts) => { }) as typeof zed.zq export const createReadableStream = ((opts) => { - return zed.createReadableStream({...opts, bin: zdeps.zq}) + return zed.createReadableStream({...opts, bin: zdeps.superdb}) }) as typeof zed.createReadableStream diff --git a/apps/zui/src/domain/loads/handlers/preview-load-files.ts b/apps/zui/src/domain/loads/handlers/preview-load-files.ts index 66f8fa16d8..54e408b991 100644 --- a/apps/zui/src/domain/loads/handlers/preview-load-files.ts +++ b/apps/zui/src/domain/loads/handlers/preview-load-files.ts @@ -2,31 +2,22 @@ import {createHandler} from "src/core/handlers" import Current from "src/js/state/Current" import LoadDataForm from "src/js/state/LoadDataForm" import Pools from "src/js/state/Pools" -import {quickLoadFiles} from "./quick-load-files" import Modal from "src/js/state/Modal" export const previewLoadFiles = createHandler( "loads.previewLoadFiles", - async ( - {dispatch, invoke, select}, - opts: {files: string[]; poolId?: string} - ) => { - const files = await invoke("loads.getFileTypes", opts.files) + async ({dispatch, select}, opts: {files: string[]; poolId?: string}) => { const lakeId = select(Current.getLakeId) const pool = select(Pools.get(lakeId, opts.poolId)) const poolId = pool ? pool.id : null - if (files.length === 1 && files[0].type === "pcap") { - quickLoadFiles({files: files.map((f) => f.path), poolId}) + if (select(LoadDataForm.getShow)) { + // The preview load is already opened + dispatch(LoadDataForm.addFiles(opts.files)) } else { - if (select(LoadDataForm.getShow)) { - // The preview load is already opened - dispatch(LoadDataForm.addFiles(opts.files)) - } else { - dispatch(LoadDataForm.setFiles(opts.files)) - dispatch(LoadDataForm.setPoolId(poolId)) - dispatch(Modal.show("preview-load")) - } + dispatch(LoadDataForm.setFiles(opts.files)) + dispatch(LoadDataForm.setPoolId(poolId)) + dispatch(Modal.show("preview-load")) } } ) diff --git a/apps/zui/src/domain/loads/messages.ts b/apps/zui/src/domain/loads/messages.ts index 0e7d33fe0d..8062ba4c65 100644 --- a/apps/zui/src/domain/loads/messages.ts +++ b/apps/zui/src/domain/loads/messages.ts @@ -19,7 +19,6 @@ export type LoadFormData = { export type LoadsOperations = { "loads.create": typeof ops.create "loads.preview": typeof ops.preview - "loads.getFileTypes": typeof ops.getFileTypes "loads.abortPreview": typeof ops.abortPreview "loads.abort": typeof ops.abort "loads.paste": typeof ops.paste diff --git a/apps/zui/src/domain/loads/operations/create.ts b/apps/zui/src/domain/loads/operations/create.ts index ab2febc90c..a87bfd3739 100644 --- a/apps/zui/src/domain/loads/operations/create.ts +++ b/apps/zui/src/domain/loads/operations/create.ts @@ -1,7 +1,6 @@ import {createOperation} from "src/core/operations" import * as zui from "src/zui" import {Pool} from "src/models/pool" -import {ZedScript} from "src/models/zed-script" import {LoadFormData} from "../messages" import {errorToString} from "src/util/error-to-string" import {deriveName} from "src/domain/pools/utils" diff --git a/apps/zui/src/domain/loads/operations/get-file-types.ts b/apps/zui/src/domain/loads/operations/get-file-types.ts deleted file mode 100644 index 84610d3847..0000000000 --- a/apps/zui/src/domain/loads/operations/get-file-types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {createOperation} from "src/core/operations" -import {isPcap} from "src/plugins/brimcap/packets/is-pcap" - -async function getFileType(path: string) { - if (await isPcap(path)) return {type: "pcap", path} - else return {type: "text", path} -} - -export const getFileTypes = createOperation( - "loads.getFileTypes", - async (_, paths: string[]) => { - const data = [] - for (const path of paths) data.push(await getFileType(path)) - return data - } -) diff --git a/apps/zui/src/domain/loads/operations/index.ts b/apps/zui/src/domain/loads/operations/index.ts index 87f1038cc0..c7ff8bb3ee 100644 --- a/apps/zui/src/domain/loads/operations/index.ts +++ b/apps/zui/src/domain/loads/operations/index.ts @@ -1,4 +1,3 @@ -export * from "./get-file-types" export * from "./preview" export * from "./create" export * from "./abort" diff --git a/apps/zui/src/models/snapshot/source-set.ts b/apps/zui/src/models/snapshot/source-set.ts index 9d4f6a5149..727cee5743 100644 --- a/apps/zui/src/models/snapshot/source-set.ts +++ b/apps/zui/src/models/snapshot/source-set.ts @@ -9,8 +9,6 @@ export class SourceSet { .concat(mainText) .filter((snippet) => snippet.trim().length) .forEach((snippet) => this.appendSource(snippet)) - - if (!this.sources.length) this.appendSource("*") } appendSource(text: string) { diff --git a/apps/zui/src/plugins/brimcap/analyze.ts b/apps/zui/src/plugins/brimcap/analyze.ts deleted file mode 100644 index be493df486..0000000000 --- a/apps/zui/src/plugins/brimcap/analyze.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {compact} from "lodash" -import {configurations} from "src/zui" -import {pluginNamespace, yamlConfigPropName} from "./config" -import {AnalyzeOptions, createCli} from "./cli" - -function getAnalyzeOptions(): AnalyzeOptions { - return { - json: true, - config: configurations.get(pluginNamespace, yamlConfigPropName) || "", - } -} - -export function createAnalyzeProcess(signal) { - const cli = createCli() - const sub = cli.analyze("-", getAnalyzeOptions(), signal) - return sub -} - -export function monitorAnalyzeProgress(analyzeProc, callback) { - analyzeProc.stderr - .once("data", () => analyzeProc.stdout.emit("start")) - .on("data", (data) => { - const lines = compact(data.toString().split("\n")) as string[] - const stats = lines.map((line) => JSON.parse(line)) - stats.forEach(callback) - }) -} diff --git a/apps/zui/src/plugins/brimcap/cli.ts b/apps/zui/src/plugins/brimcap/cli.ts deleted file mode 100644 index 9a7209a681..0000000000 --- a/apps/zui/src/plugins/brimcap/cli.ts +++ /dev/null @@ -1,126 +0,0 @@ -import {env} from "src/zui" -import {spawnSync, spawn, ChildProcess} from "child_process" -import {compact, isEmpty} from "lodash" -import flatMap from "lodash/flatMap" - -interface PacketOptions { - dstIp?: string - dstPort?: string - duration?: string - proto?: string - srcIp?: string - srcPort?: string - ts?: string -} - -export interface IndexOptions { - root: string - pcap: string -} - -export interface AnalyzeOptions { - config?: string - suricataDisabled?: boolean - suricataStderr?: string - suricataStdout?: string - zeekDisabled?: boolean - zeekStdout?: string - zeekStderr?: string - utf8?: boolean - showTypes?: boolean - showFields?: boolean - color?: boolean - lz4Blocksize?: number - pretty?: number - columnThresh?: number - skewThresh?: number - dir?: string - out?: string - json?: boolean -} - -export interface SearchOptions extends PacketOptions { - root: string - write: string -} - -const OPTION_NAME_MAP = { - pool: "p", - suricataDisabled: "analyzers.suricata.disabled", - suricataStderr: "analyzers.suricata.stderr", - suricataStdout: "analyzers.suricata.stdout", - zeekDisabled: "analyzers.zeek.disabled", - zeekStdout: "analyzers.zeek.stdout", - zeekStderr: "analyzers.zeek.stderr", - write: "w", - dstIp: "dst.ip", - dstPort: "dst.port", - srcIp: "src.ip", - srcPort: "src.port", - utf8: "U", - showTypes: "T", - showFields: "F", - lz4Blocksize: "znglz4blocksize", - pretty: "pretty", - columnThresh: "coltresh", - skewThresh: "skewtresh", - dir: "d", - out: "o", - pcap: "r", -} - -const toCliOpts = ( - opts: SearchOptions | AnalyzeOptions | IndexOptions -): string[] => - compact( - flatMap( - Object.entries(opts).map(([k, v]) => { - const optKey = `-${OPTION_NAME_MAP[k] || k}` - // booleans flags don't use values, if opting in just include the key - if (typeof v === "boolean" && v) return [optKey] - // otherwise, if no value provided, don't include this option - if (isEmpty(v)) return - - return [optKey, v] - }) - ) - ) - -export default class BrimcapCLI { - private isWin = env.isWindows - // don't detach if is windows - private spawnOpts = this.isWin ? undefined : {detached: true} - - constructor(private binPath: string) {} - - index(opts: IndexOptions) { - return this.execSpawnSync("index", [...toCliOpts(opts)]) - } - - analyze( - pcapPath: string, - opts: AnalyzeOptions, - signal?: AbortSignal - ): ChildProcess { - return this.execSpawn("analyze", [...toCliOpts(opts), pcapPath], signal) - } - - search(opts: SearchOptions) { - return this.execSpawnSync("search", [...toCliOpts(opts)]) - } - - private execSpawn(subCommand: string, optsAndArgs: string[], signal) { - return spawn(this.binPath, [subCommand, ...optsAndArgs], { - ...this.spawnOpts, - signal, - }) - } - - private execSpawnSync(subCommand: string, opts: string[]) { - return spawnSync(this.binPath, [subCommand, ...opts]) - } -} - -export function createCli() { - return new BrimcapCLI(env.getExePath("brimcap")) -} diff --git a/apps/zui/src/plugins/brimcap/config.ts b/apps/zui/src/plugins/brimcap/config.ts index 74c8b61b73..af3c153a47 100644 --- a/apps/zui/src/plugins/brimcap/config.ts +++ b/apps/zui/src/plugins/brimcap/config.ts @@ -1,4 +1 @@ export const pluginNamespace = "brimcap" -export const yamlConfigPropName = "yamlConfigPath" -export const suricataLocalRulesPropName = "suricataLocalRulesPath" -export const pcapFolderPropName = "pcapExtractionFolderPath" diff --git a/apps/zui/src/plugins/brimcap/configurations.ts b/apps/zui/src/plugins/brimcap/configurations.ts deleted file mode 100644 index e574a591cf..0000000000 --- a/apps/zui/src/plugins/brimcap/configurations.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - pluginNamespace, - yamlConfigPropName, - suricataLocalRulesPropName, - pcapFolderPropName, -} from "./config" -import {configurations} from "src/zui" - -export function activateBrimcapConfigurations() { - configurations.create({ - name: pluginNamespace, - title: "Packet Captures", - properties: { - [yamlConfigPropName]: { - name: yamlConfigPropName, - type: "file", - label: "Brimcap YAML Config File", - defaultValue: "", - helpLink: { - label: "docs", - url: "https://zui.brimdata.io/docs/features/Packet-Captures#brimcap-yaml-config-file", - }, - }, - [suricataLocalRulesPropName]: { - name: suricataLocalRulesPropName, - type: "folder", - label: "Local Suricata Rules Folder", - defaultValue: "", - helpLink: { - label: "docs", - url: "https://zui.brimdata.io/docs/features/Packet-Captures#local-suricata-rules-folder", - }, - }, - [pcapFolderPropName]: { - name: pcapFolderPropName, - type: "folder", - label: "Folder For Extracted pcaps", - defaultValue: "", - placeholder: "Default OS tmpdir", - helpLink: { - label: "docs", - url: "https://zui.brimdata.io/docs/features/Packet-Captures#folder-for-extracted-pcaps", - }, - }, - }, - }) -} diff --git a/apps/zui/src/plugins/brimcap/configure-zeek-pool.ts b/apps/zui/src/plugins/brimcap/configure-zeek-pool.ts deleted file mode 100644 index 9469e420fe..0000000000 --- a/apps/zui/src/plugins/brimcap/configure-zeek-pool.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {zeekColorMap} from "./zeek/colors" -import {pools} from "src/zui" - -export function configureZeekPool(poolId: string) { - pools - .configure(poolId) - .set("timeField", "ts") - .set("colorField", "_path") - .set("colorMap", zeekColorMap) -} diff --git a/apps/zui/src/plugins/brimcap/index.ts b/apps/zui/src/plugins/brimcap/index.ts index f34ff13e83..a92b604c40 100644 --- a/apps/zui/src/plugins/brimcap/index.ts +++ b/apps/zui/src/plugins/brimcap/index.ts @@ -1,25 +1,8 @@ import {PluginContext} from "src/zui" -import {activateBrimcapLoader} from "./loader" -import {activateSuricataUpdater} from "./suricata/update" -import {activateDownloadPacketsCommand} from "./packets/download" -import {activatePacketsMenuItem} from "./packets/menu-item" -import {activateBrimcapConfigurations} from "./configurations" import {activateSuricataCorrelations} from "./suricata/correlations" import {activateZeekCorrelations} from "./zeek/correlations" -import {activateStorage} from "./storage" -export function activate(ctx: PluginContext) { - const {root, suricata} = activateStorage(ctx) - - // suricataupdater and suricatarunner (run by "brimcap analyze") - // both consult BRIM_SURICATA_USER_DIR. - process.env.BRIM_SURICATA_USER_DIR = suricata - - activatePacketsMenuItem() - activateDownloadPacketsCommand(root) +export function activate(_ctx: PluginContext) { activateSuricataCorrelations() activateZeekCorrelations() - activateBrimcapLoader(root) - activateBrimcapConfigurations() - activateSuricataUpdater() } diff --git a/apps/zui/src/plugins/brimcap/loader.ts b/apps/zui/src/plugins/brimcap/loader.ts deleted file mode 100644 index 31061223a9..0000000000 --- a/apps/zui/src/plugins/brimcap/loader.ts +++ /dev/null @@ -1,97 +0,0 @@ -import fs from "fs" -import {LoadContext} from "src/domain/loads/load-context" -import {isPcap} from "./packets/is-pcap" -import {loads} from "src/zui" -import {pipeline} from "stream" -import {createTransform} from "./transform-stream" -import {configureZeekPool} from "./configure-zeek-pool" -import {createAnalyzeProcess, monitorAnalyzeProgress} from "./analyze" -import {createCli} from "./cli" -import errors from "src/js/errors" -import {errorToString} from "src/util/error-to-string" -import {Loader} from "src/domain/loads/types" - -class BrimcapLoader implements Loader { - constructor(private ctx: LoadContext, private root: string) {} - - async when() { - const file = this.ctx.files[0] - return file && (await isPcap(file)) - } - - async run() { - if (this.ctx.files.length > 1) { - throw new Error("Only one PCAP can be loaded at a time") - } - this.ctx.setProgress(0) - await this.load(this.startPipeline()) - this.index() - configureZeekPool(this.ctx.poolId) - this.ctx.setProgress(1) - } - - startPipeline() { - return pipeline(fs.createReadStream(this.pcap), this.analyze(), (err) => { - if (err) { - this.ctx.abort() - this.ctx.addError(errorToString(err)) - } - }) - } - - analyze() { - const process = createAnalyzeProcess(this.ctx.signal) - const stream = createTransform(process) - const totalSize = fs.statSync(this.pcap).size - monitorAnalyzeProgress(process, ({type, ...status}) => { - switch (type) { - case "status": - this.ctx.setProgress(status.pcap_read_size / totalSize || 0) - this.ctx.onPoolChanged() - break - case "warning": - if (status.warning) this.ctx.addError(status.warning) - break - case "error": - if (status.error) stream.destroy(new Error(status.error)) - break - } - }) - return stream - } - - index() { - const cli = createCli() - try { - cli.index({root: this.root, pcap: this.pcap}) - } catch (e) { - console.error(e) - throw errors.pcapIngest(e) - } - } - - async load(streamBody: NodeJS.ReadableStream) { - const client = await this.ctx.createClient() - const {ctx} = this - const author = "zui" - const body = "Automatic Import with brimcap analyze" - const pool = ctx.poolId - const {branch, signal} = ctx - return client.load(streamBody, { - message: {author, body}, - pool, - branch, - signal, - }) - } - - get pcap() { - return this.ctx.files[0] - } -} - -export function activateBrimcapLoader(root: string) { - loads.addLoader("brimcap-loader", (ctx: LoadContext) => { - return new BrimcapLoader(ctx, root) - }) -} diff --git a/apps/zui/src/plugins/brimcap/packets/download.ts b/apps/zui/src/plugins/brimcap/packets/download.ts deleted file mode 100644 index 59ed23bc5e..0000000000 --- a/apps/zui/src/plugins/brimcap/packets/download.ts +++ /dev/null @@ -1,62 +0,0 @@ -import * as zed from "@brimdata/zed-js" -import {join} from "path" -import {createCli} from "../cli" -import os from "os" -import {window, commands} from "src/zui" -import {queryForConnLog} from "./query-conn-log" -import {DOWNLOAD} from "./types" -import {shell} from "electron" -import {configurations} from "src/zui" -import {pluginNamespace, pcapFolderPropName} from "../config" - -function getSearchArgsFromConn(conn: zed.Record) { - const dur = conn.try("duration") as zed.Duration - return { - dstIp: conn.get(["id", "resp_h"]).toString(), - dstPort: conn.get(["id", "resp_p"]).toString(), - duration: dur?.isSet() ? dur.toString() : "0s", - proto: conn.get("proto").toString(), - srcIp: conn.get(["id", "orig_h"]).toString(), - srcPort: conn.get(["id", "orig_p"]).toString(), - ts: conn.get("ts").toString(), - } -} - -function getPacketDest(conn: zed.Record) { - const tsString = conn.get("ts").toString() - const pcapExtractionDir = - configurations.get(pluginNamespace, pcapFolderPropName) || os.tmpdir() - return join(pcapExtractionDir, `packets-${tsString}.pcap`.replace(/:/g, "_")) -} - -export async function downloadPackets(root: string, pool: string, uid: string) { - const conn = await queryForConnLog(pool, uid) - if (conn) { - const args = getSearchArgsFromConn(conn) - const dest = getPacketDest(conn) - const cli = createCli() - const result = cli.search({...args, write: dest, root}) - - if (result.status > 0) { - const err = result.stderr.toString() - console.error(err) - const msg = JSON.parse(err)?.error || `brimcap search failed: ${err}` - window.showErrorMessage(msg) - } else { - const msg = await shell.openPath(dest) - if (msg) { - window.showErrorMessage( - "Could not open extracted pcap. Is Wireshark installed?" - ) - } else { - window.showSuccessMessage("Packets extracted. Opening...") - } - } - } -} - -export function activateDownloadPacketsCommand(packetsDir: string) { - commands.create(DOWNLOAD, (pool: string, uid: string) => - downloadPackets(packetsDir, pool, uid) - ) -} diff --git a/apps/zui/src/plugins/brimcap/packets/is-pcap.ts b/apps/zui/src/plugins/brimcap/packets/is-pcap.ts deleted file mode 100644 index 9ac757a991..0000000000 --- a/apps/zui/src/plugins/brimcap/packets/is-pcap.ts +++ /dev/null @@ -1,29 +0,0 @@ -import fs from "fs" - -const PCAP_1_HEX = "d4c3b2a1" -const PCAP_2_HEX = "a1b2c3d4" -const PCAPNG_HEX = "0a0d0d0a" -const PCAPNANO_HEX = "4d3cb2a1" -const PCAP_HEXES = [PCAP_1_HEX, PCAP_2_HEX, PCAPNG_HEX, PCAPNANO_HEX] - -function firstBytes(filePath: string, n: number) { - return new Promise((res, rej) => { - const stream = fs.createReadStream(filePath) - stream - .on("readable", () => { - let buffer = stream.read(n) - stream.destroy() - res(buffer) - }) - .on("error", rej) - }) -} - -export async function isPcap(filePath: string) { - let bytes = await firstBytes(filePath, 4) - for (let hex of PCAP_HEXES) { - if (bytes instanceof Buffer && bytes.equals(Buffer.from(hex, "hex"))) - return true - } - return false -} diff --git a/apps/zui/src/plugins/brimcap/packets/menu-item.ts b/apps/zui/src/plugins/brimcap/packets/menu-item.ts deleted file mode 100644 index e1a83945d4..0000000000 --- a/apps/zui/src/plugins/brimcap/packets/menu-item.ts +++ /dev/null @@ -1,44 +0,0 @@ -import {MenuItem, menus, session} from "src/zui" -import {DOWNLOAD, DownloadArgs} from "./types" -import * as zed from "@brimdata/zed-js" -import {findUid} from "../zeek/util" -import {queryForConnLog} from "./query-conn-log" - -const MENU_NAME = "results.toolbarMenu" - -const packetsMenuItem: MenuItem = { - id: "packets", - iconName: "wireshark", - label: "Packets", - description: "Download Packets", - command: DOWNLOAD as any, - enabled: false, -} - -async function onSelectionChange({row}) { - if (row instanceof zed.Record) { - const uid = findUid(row) - const pool = session.poolName - let enabled = false - if (uid && pool) { - const conn = await queryForConnLog(pool, uid) - if (conn) { - enabled = true - } - } - const id = packetsMenuItem.id - menus.updateItem(MENU_NAME, id, { - enabled, - args: [pool, uid] as DownloadArgs, - }) - } -} - -export function activatePacketsMenuItem() { - session.on("result-selection-change", onSelectionChange) - menus.extend(MENU_NAME, (menu: MenuItem[]) => { - const index = menu.findIndex((item) => item.id == "export-results") - menu.splice(index, 0, packetsMenuItem) - return menu - }) -} diff --git a/apps/zui/src/plugins/brimcap/packets/query-conn-log.ts b/apps/zui/src/plugins/brimcap/packets/query-conn-log.ts deleted file mode 100644 index 2eef05b5ed..0000000000 --- a/apps/zui/src/plugins/brimcap/packets/query-conn-log.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {lake} from "src/zui" -import {findConnLog} from "../zeek/queries" -import * as zed from "@brimdata/zed-js" - -export async function queryForConnLog(pool: string, uid: string) { - const query = findConnLog(pool, uid) - const results = await lake.query(query).then((r) => r.zed()) - const [conn] = results - return conn as zed.Record -} diff --git a/apps/zui/src/plugins/brimcap/packets/types.ts b/apps/zui/src/plugins/brimcap/packets/types.ts deleted file mode 100644 index 48c3ed550f..0000000000 --- a/apps/zui/src/plugins/brimcap/packets/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type DownloadArgs = [pool: string, uid: string] -export const DOWNLOAD = "brimcap.downloadPackets" diff --git a/apps/zui/src/plugins/brimcap/storage.ts b/apps/zui/src/plugins/brimcap/storage.ts deleted file mode 100644 index e15af2dc84..0000000000 --- a/apps/zui/src/plugins/brimcap/storage.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {PluginContext} from "src/zui" -import {join} from "path" -import {ensureDirSync} from "fs-extra" - -export function setupPacketsRoot(ctx: PluginContext) { - const root = join(ctx.storagePath, "root") - ensureDirSync(root) - return root -} - -export function setupSuricataRoot(ctx: PluginContext) { - const root = join(ctx.storagePath, "suricata") - ensureDirSync(root) - // suricataupdater and suricatarunner (run by "brimcap analyze") - // both consult BRIM_SURICATA_USER_DIR. - process.env.BRIM_SURICATA_USER_DIR = root - return root -} - -export function activateStorage(ctx: PluginContext) { - return { - suricata: setupSuricataRoot(ctx), - root: setupPacketsRoot(ctx), - } -} diff --git a/apps/zui/src/plugins/brimcap/suricata/update.ts b/apps/zui/src/plugins/brimcap/suricata/update.ts deleted file mode 100644 index 443786a220..0000000000 --- a/apps/zui/src/plugins/brimcap/suricata/update.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {env} from "src/zui" -import {configurations} from "src/zui" -import {spawn, ChildProcess} from "child_process" -import {error, debug} from "electron-log" -import {pluginNamespace, suricataLocalRulesPropName} from "../config" - -let proc: ChildProcess = null - -function updateSuricata(suricataLocalRulesPath) { - const exe = env.getExePath("suricata/suricataupdater") - - if (suricataLocalRulesPath) { - proc = spawn(exe, ["--local", suricataLocalRulesPath]) - } else { - proc = spawn(exe) - } - - proc - .on("error", (e) => { - error(`Error updating Suricata rules: ${e.message || e}`) - }) - .on("close", () => { - debug("Closing suricata updater") - }) -} - -export function activateSuricataUpdater() { - if (env.isTest) return - configurations.watch( - pluginNamespace, - suricataLocalRulesPropName, - (suricataLocalRulesPath) => { - updateSuricata(suricataLocalRulesPath) - } - ) -} diff --git a/apps/zui/src/plugins/brimcap/transform-stream.ts b/apps/zui/src/plugins/brimcap/transform-stream.ts deleted file mode 100644 index bab619a86d..0000000000 --- a/apps/zui/src/plugins/brimcap/transform-stream.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {ChildProcessWithoutNullStreams} from "node:child_process" -import {Stream} from "node:stream" -import {isAbortError} from "src/util/is-abort-error" - -export function createTransform(sub: ChildProcessWithoutNullStreams) { - const stream = new Stream.Transform({ - transform(chunk, encoding, callback) { - if (!sub.stdin.write(chunk, encoding)) { - sub.stdin.once("drain", callback) - } else { - process.nextTick(callback) - } - }, - - flush(callback) { - sub.stdin.end() - if (sub.stdout.destroyed) callback() - else sub.stdout.on("close", () => callback()) - }, - }) - // Transform stream handlers - stream.on("error", () => { - sub.kill("SIGKILL") - }) - - // Sub Hanlers - sub.on("error", (e) => { - if (isAbortError(e)) return - stream.destroy(e) - }) - - // STDIN HANLDERS - sub.stdin.on("error", (e: Error & {code: string}) => { - e.code === "EPIPE" ? stream.push(null) : stream.destroy(e) - }) - - // STDOUT HANLDERS - sub.stdout - .on("data", (data) => stream.readable && stream.push(data)) - .on("error", (e) => stream.destroy(e)) - - // STDERR HANLDERS - sub.stderr.on("error", (e) => stream.destroy(e)) - return stream -} diff --git a/apps/zui/src/views/results-pane/error.tsx b/apps/zui/src/views/results-pane/error.tsx index aacd1573ae..41873c59bf 100644 --- a/apps/zui/src/views/results-pane/error.tsx +++ b/apps/zui/src/views/results-pane/error.tsx @@ -1,12 +1,12 @@ import React from "react" import {DefaultError} from "./errors/default-error" -import {isMissingPoolError, MissingPoolError} from "./errors/missing-pool-error" import {isParseError, SyntaxError} from "./errors/syntax-error" import {isNetworkError, NetworkError} from "./errors/network-error" +import {isEmptyQueryError} from "./errors/empty-query" export function Error(props: {error: string | object}) { + if (isEmptyQueryError(props.error)) return null if (isParseError(props.error)) return - if (isMissingPoolError(props.error)) return if (isNetworkError(props.error)) return return } diff --git a/apps/zui/src/views/results-pane/errors/empty-query.tsx b/apps/zui/src/views/results-pane/errors/empty-query.tsx new file mode 100644 index 0000000000..fd95948f63 --- /dev/null +++ b/apps/zui/src/views/results-pane/errors/empty-query.tsx @@ -0,0 +1,3 @@ +export function isEmptyQueryError(obj: any) { + return obj == "query text is missing" +} diff --git a/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx b/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx deleted file mode 100644 index c1045a3ff2..0000000000 --- a/apps/zui/src/views/results-pane/errors/missing-pool-error.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import React from "react" -import {useSelector} from "react-redux" -import {Icon} from "src/components/icon" -import {Pool} from "src/models/pool" -import {Item} from "src/views/sidebar/item" -import useLakeId from "src/app/router/hooks/use-lake-id" -import {Content} from "src/js/components/Content" -import {VirtualList} from "src/js/components/virtual-list" -import Pools from "src/js/state/Pools" -import {State} from "src/js/state/types" -import styled from "styled-components" -import {newPool} from "src/domain/pools/handlers" -import {setFromPin} from "src/domain/session/handlers" - -const BG = styled.div` - width: 100%; - height: 100%; - background-repeat: no-repeat; - background-position-x: 95%; - background-position-y: 250px; - padding-left: 10%; - padding-top: 50px; - overflow: auto; - display: flex; - flex-direction: column; -` - -const Message = styled(Content)` - margin-top: 30px; - width: 320px; -` - -const Card = styled.section` - display: flex; - flex-direction: column; - align-items: center; - margin-top: 50px; - width: 320px; - overflow: hidden; - border-radius: 8px; - box-shadow: 0 0 0 1px var(--border-color); - flex: 1; - margin-bottom: 30px; -` - -export function isMissingPoolError(e: unknown) { - return typeof e === "string" && /no pool name given/.test(e) -} - -function PoolsList({pools}: {pools: Pool[]}) { - const rowHeight = 32 - - return ( - - - {(props) => { - return ( - } - onClick={() => setFromPin(props.item.name)} - aria={props.aria} - /> - ) - }} - - - ) -} - -function NoPoolsMessage() { - return ( - <> - - { - "You don't have any pools yet. Load data into a pool to start querying." - } - - - - - - ) -} - -function SomePoolsMessage(props: {pools: Pool[]}) { - return ( - <> - - { - "Add a from clause to your query, or click one of the pools below to create a 'from' pin in your query." - } - - - - ) -} - -export function MissingPoolError() { - const lakeId = useLakeId() - const pools = useSelector((state: State) => Pools.all(state, lakeId)) - return ( - -

No Pool Specified

- {pools.length ? : } -
- ) -} diff --git a/apps/zui/src/views/results-pane/run-results-query.tsx b/apps/zui/src/views/results-pane/run-results-query.tsx index 610c9c1396..b8b52aabfe 100644 --- a/apps/zui/src/views/results-pane/run-results-query.tsx +++ b/apps/zui/src/views/results-pane/run-results-query.tsx @@ -10,6 +10,7 @@ export const runResultsMain = createHandler( async ({select, dispatch, waitForSelector}) => { const query = Active.snapshot.queryText const tabId = select(Current.getTabId) + console.log(query) dispatch(firstPage({id: RESULTS_QUERY, query})) // See if we can paginate this query diff --git a/packages/zui-player/tests/no-pool-specified.spec.ts b/packages/zui-player/tests/no-pool-specified.spec.ts deleted file mode 100644 index 4611d58958..0000000000 --- a/packages/zui-player/tests/no-pool-specified.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { expect, test } from '@playwright/test'; -import TestApp from '../helpers/test-app'; -import { getPath } from 'zui-test-data'; - -test.describe('No Pool Specified State', () => { - const app = new TestApp('No Pool Specified'); - - test.beforeAll(async () => { - await app.init(); - }); - - test.afterAll(async () => { - await app.shutdown(); - }); - - test('Query missing a from with no pools', async () => { - await app.click('button', 'create'); - await app.click('listitem', 'New Query Session'); - await app.attached(/load data into a pool/i); - }); - - test('Query missing a from with some pools', async () => { - await app.createPool([getPath('small-zeek.zng')]); - await app.click('button', 'create'); - await app.click('listitem', 'New Query Session'); - - await app.attached(/click one of the pools/i); - - await app.attached('list', 'from-pin-list'); - await app.click('listitem', 'small-zeek.zng'); - - const stats = await app.getViewerStats(); - expect(stats).toEqual({ results: 31, shapes: 8 }); - }); -}); diff --git a/packages/zui-player/tests/packets.spec.ts b/packages/zui-player/tests/packets.spec.ts index 96b06358bf..b9be2672a2 100644 --- a/packages/zui-player/tests/packets.spec.ts +++ b/packages/zui-player/tests/packets.spec.ts @@ -1,35 +1,11 @@ import { play } from 'zui-player'; import { getPath } from 'zui-test-data'; -import { isCI } from '../helpers/env'; // Timeouts are increased due to observed long pcap load times in CI. // See https://github.com/brimdata/zui/pull/2978 play('packets.spec', (app, test) => { - test('dropping a pcap does not pop up preview and load', async () => { - if (isCI()) { - test.setTimeout(2 * 60_000); - app.page.setDefaultTimeout(2 * 60_000); - } + test('dropping a pcap throw an error now', async () => { await app.dropFile(getPath('sample.pcap')); - await app.attached(/Successfully loaded into sample.pcap/); + await app.attached(/Error Reading Data/); }); - - test('getting a slice of the packets back', async () => { - await app.click('button', 'Query Pool'); - await app.query('fuse'); - - await app.click('gridcell', 'conn'); - await app.click('button', 'Packets'); - await app.attached(/Packets extracted. Opening.../); - }); - - test('loading a bad (Wireshark-unreadable) pcap displays an error message', async () => { - if (isCI()) { - test.setTimeout(2 * 60_000); - app.page.setDefaultTimeout(2 * 60_000); - } - await app.dropFile(getPath('bad.pcapng')); - await app.attached(/with 1 error/); - }); - });