Skip to content

Commit

Permalink
Cp add quest beacon filter (#697)
Browse files Browse the repository at this point in the history
* feat(quests): Implement more complext filtering to quests

* fix(build): Rebuild UI
  • Loading branch information
cmp5987 authored Mar 10, 2024
1 parent d033249 commit aaa84f3
Show file tree
Hide file tree
Showing 22 changed files with 433 additions and 203 deletions.
6 changes: 3 additions & 3 deletions tavern/internal/www/build/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"files": {
"main.css": "/static/css/main.c8dfb028.css",
"main.js": "/static/js/main.b7b5296b.js",
"main.js": "/static/js/main.f97381e4.js",
"react-syntax-highlighter/refractor-core-import.js": "/static/js/react-syntax-highlighter/refractor-core-import.d0cd1e85.chunk.js",
"react-syntax-highlighter_languages_refractor_abap.js": "/static/js/react-syntax-highlighter_languages_refractor_abap.a2bf84e3.chunk.js",
"react-syntax-highlighter_languages_refractor_actionscript.js": "/static/js/react-syntax-highlighter_languages_refractor_actionscript.fff5a604.chunk.js",
Expand Down Expand Up @@ -158,7 +158,7 @@
"static/media/eldrich.png": "/static/media/eldrich.a80c74e8249d2461e174.png",
"index.html": "/index.html",
"main.c8dfb028.css.map": "/static/css/main.c8dfb028.css.map",
"main.b7b5296b.js.map": "/static/js/main.b7b5296b.js.map",
"main.f97381e4.js.map": "/static/js/main.f97381e4.js.map",
"refractor-core-import.d0cd1e85.chunk.js.map": "/static/js/react-syntax-highlighter/refractor-core-import.d0cd1e85.chunk.js.map",
"react-syntax-highlighter_languages_refractor_abap.a2bf84e3.chunk.js.map": "/static/js/react-syntax-highlighter_languages_refractor_abap.a2bf84e3.chunk.js.map",
"react-syntax-highlighter_languages_refractor_actionscript.fff5a604.chunk.js.map": "/static/js/react-syntax-highlighter_languages_refractor_actionscript.fff5a604.chunk.js.map",
Expand Down Expand Up @@ -315,6 +315,6 @@
},
"entrypoints": [
"static/css/main.c8dfb028.css",
"static/js/main.b7b5296b.js"
"static/js/main.f97381e4.js"
]
}
2 changes: 1 addition & 1 deletion tavern/internal/www/build/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Realm - Red Team Engagement Platform</title><script defer="defer" src="/static/js/main.b7b5296b.js"></script><link href="/static/css/main.c8dfb028.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Realm - Red Team Engagement Platform</title><script defer="defer" src="/static/js/main.f97381e4.js"></script><link href="/static/css/main.c8dfb028.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
3 changes: 0 additions & 3 deletions tavern/internal/www/build/static/js/main.b7b5296b.js

This file was deleted.

3 changes: 3 additions & 0 deletions tavern/internal/www/build/static/js/main.f97381e4.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions tavern/internal/www/src/components/FilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import FreeTextSearch from "./tavern-base-ui/DebouncedFreeTextSearch";
import { FilterBarOption } from "../utils/consts";

type Props = {
searchPlaceholder?: string;
setSearch: (arg: string) => void;
setFiltersSelected: (arg: Array<any>) => void;
filtersSelected: Array<FilterBarOption>
}
const FilterBar = (props: Props) => {
const { setSearch, setFiltersSelected, filtersSelected } = props;

const { searchPlaceholder, setSearch, setFiltersSelected, filtersSelected } = props;
const { data, isLoading, error } = useContext(TagContext);

return (
<div>
{(!isLoading && !error && data) && (
<div className="grid grid-cols-2 gap-2">
<FreeTextSearch setSearch={setSearch} />
<FreeTextSearch setSearch={setSearch} placeholder={searchPlaceholder} />
<BeaconFilterBar beacons={data?.beacons || []} groups={data?.groupTags || []} services={data?.serviceTags || []} hosts={data?.hosts || []} setFiltersSelected={setFiltersSelected} filtersSelected={filtersSelected} />
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
BugAntIcon,
PresentationChartBarIcon,
BookOpenIcon,
DocumentTextIcon,
ClipboardDocumentListIcon,
} from '@heroicons/react/24/outline'

Expand All @@ -23,7 +22,6 @@ const navigation = [
{ name: PageNavItem.dashboard, href: '/dashboard', icon: PresentationChartBarIcon, internal: true },
{ name: PageNavItem.hosts, href: '/hosts', icon: BugAntIcon, internal: true },
{ name: PageNavItem.quests, href: '/quests', icon: ClipboardDocumentListIcon, internal: true },
{ name: PageNavItem.tasks, href: '/tasks', icon: DocumentTextIcon, internal: true },
{ name: PageNavItem.tomes, href: '/tomes', icon: BookOpenIcon, internal: true },
{ name: PageNavItem.documentation, href: 'https://docs.realm.pub/', icon: DocumentDuplicateIcon, target: "__blank", internal: false },
{ name: PageNavItem.playground, href: '/playground', icon: WrenchScrewdriverIcon, target: "__blank", internal: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ type Props = {
}
const FreeTextSearch = (props: Props) => {
const { placeholder, questId } = useParams();
const placeholderText = placeholder ? placeholder : questId ? "Search by output" : "Search by tome name, quest name, or output";
const { setSearch } = props;
const { placeholder: parentPlaceholder, setSearch } = props;
const placeholderText = parentPlaceholder ? parentPlaceholder : placeholder ? placeholder : questId ? "Search by output" : "Search by tome name, quest name, or output";

const debouncedSearch = useRef(
debounce(async (criteria) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Fragment } from 'react'
import { ChevronDownIcon } from '@heroicons/react/20/solid'
import { Button } from '@chakra-ui/react'
import { EllipsisHorizontalIcon } from '@heroicons/react/24/outline'
import { Task, Tome } from '../../utils/consts'
import { Tome } from '../../utils/consts'
import { LimitedTaskNode, useCreateQuest } from './useCreateQuest'


Expand Down
271 changes: 271 additions & 0 deletions tavern/internal/www/src/hooks/useQuests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import { useQuery } from "@apollo/client";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useLocation } from "react-router-dom";
import { FilterBarOption } from "../utils/consts";
import { TableRowLimit } from "../utils/enums";
import { GET_QUEST_BY_ID_QUERY, GET_QUEST_QUERY } from "../utils/queries";
import { getFilterNameByTypes } from "../utils/utils";

export const useQuests = (pagination: boolean, id?: string) => {
const {state} = useLocation();
const [page, setPage] = useState<number>(1);
const [search, setSearch] = useState("");

const defaultFilter = useMemo(() : Array<FilterBarOption> => {
const allTrue = state && Array.isArray(state) && state.every((stateItem: FilterBarOption) => 'kind' in stateItem && 'value' in stateItem && 'name' in stateItem);
if(allTrue){
return state;
}
else{
return [];
}
},[state]);

const [filtersSelected, setFiltersSelected] = useState<Array<any>>(defaultFilter);



const handleFilterChange = (filters: Array<any>)=> {
setPage(1);
setFiltersSelected(filters);
}

const handleSearchChange = (search: string)=> {
setPage(1);
setSearch(search);
}

const constructDefaultQuery = useCallback((searchText?: string, afterCursor?: string | undefined, beforeCursor?: string | undefined) => {
const defaultRowLimit = TableRowLimit.QuestRowLimit;
const query = {
"where": {
"and": [] as Array<any>
},
"whereTotalTask": {
"and": [] as Array<any>
},
"whereFinishedTask": {
"and": [
{"execFinishedAtNotNil": true}
]
},
"whereOutputTask":{
"and": [
{"outputSizeGT": 0}
]
},
"whereErrorTask": {
"and": [
{"errorNotNil": true}
]
},
firstTask: 1,
orderByTask: [{
"direction": "DESC",
"field": "LAST_MODIFIED_AT"
}],
"orderBy": [{
"direction": "DESC",
"field": "CREATED_AT"
}]
} as any;

if(pagination){
query.first = beforeCursor ? null : defaultRowLimit;
query.last = beforeCursor ? defaultRowLimit : null;
query.after = afterCursor ? afterCursor : null;
query.before = beforeCursor ? beforeCursor : null;
}

const whereParams = [];

if(id){
whereParams.push({"id": id});
}

if(searchText){
whereParams.push({
"or": [
{"nameContains": searchText},
{"hasTomeWith": {"nameContains": searchText}}
]
});
};

query.where.and = query.where.and.concat(whereParams);

return query
},[pagination, id]);

const constructBeaconFilterQuery = useCallback((query: any, beacons: any)=>{
const fq = query;

if(beacons.length > 0){
const beaconList = {
"hasBeaconWith": {"nameIn": beacons}
};

fq.where.and = fq.where.and.concat(
{
"hasTasksWith": beaconList
}
);

fq.whereFinishedTask.and = fq.whereFinishedTask.and.concat(
beaconList
);
fq.whereOutputTask.and = fq.whereOutputTask.and.concat(
beaconList
);
fq.whereErrorTask.and =fq.whereErrorTask.and.concat(
beaconList
);
fq.whereTotalTask.and = fq.whereTotalTask.and.concat(
beaconList
);

};
return fq;
},[])

const constructTagFilterQuery = useCallback((query: any, tags: any, tagKind: string)=>{
const fq = query;
if(tags.length > 0){
const tagList = {
"hasBeaconWith": { "hasHostWith": {
"hasTagsWith": {
"and": [
{"kind": tagKind},
{"nameIn": tags}
]
}
}}
};

fq.where.and = fq.where.and.concat(
{
"hasTasksWith": tagList
}
);

fq.whereFinishedTask.and = fq.whereFinishedTask.and.concat(
tagList
);
fq.whereOutputTask.and = fq.whereOutputTask.and.concat(
tagList
);
fq.whereErrorTask.and =fq.whereErrorTask.and.concat(
tagList
);
fq.whereTotalTask.and = fq.whereTotalTask.and.concat(
tagList
);
};
return fq;
},[]);

const constructHostFilterQuery = useCallback((query: any, hosts: any)=>{
const fq = query;

if(hosts.length > 0){
const hostsList = {
"hasBeaconWith": {
"hasHostWith": {"nameIn": hosts}
}
};
fq.where.and = fq.where.and.concat(
{
"hasTasksWith": hostsList
}
);
fq.whereFinishedTask.and = fq.whereFinishedTask.and.concat(
hostsList
);
fq.whereOutputTask.and = fq.whereOutputTask.and.concat(
hostsList
);
fq.whereErrorTask.and =fq.whereErrorTask.and.concat(
hostsList
);
fq.whereTotalTask.and = fq.whereTotalTask.and.concat(
hostsList
);
};
return fq;

},[]);

const constructPlatformFilterQuery = useCallback((query: any, platforms: any)=>{
const fq = query;
const platformList = {
"hasBeaconWith": {
"hasHostWith": {
"platformIn": platforms
}
}
};

if(platforms.length > 0){
fq.where.and = fq.where.and.concat(
{
"hasTasksWith": platformList
}
);
fq.whereFinishedTask.and = fq.whereFinishedTask.and.concat(
platformList
);
fq.whereOutputTask.and = fq.whereOutputTask.and.concat(
platformList
);
fq.whereErrorTask.and =fq.whereErrorTask.and.concat(
platformList
);
fq.whereTotalTask.and = fq.whereTotalTask.and.concat(
platformList
);

}
return fq;
},[]);

const constructFilterBasedQuery = useCallback((filtersSelected: Array<any>, currentQuery: any) => {
let fq = currentQuery;
const {beacon: beacons, group: groups, service: services, platform: platforms, host:hosts} = getFilterNameByTypes(filtersSelected);

fq = constructBeaconFilterQuery(fq, beacons);
fq = constructTagFilterQuery(fq, groups, "group");
fq = constructTagFilterQuery(fq, services, "service");
fq = constructHostFilterQuery(fq, hosts);
fq = constructPlatformFilterQuery(fq, platforms);

return fq;
},[constructBeaconFilterQuery, constructTagFilterQuery, constructHostFilterQuery, constructPlatformFilterQuery]);


const { loading, data, error, refetch } = useQuery(
id ? GET_QUEST_BY_ID_QUERY : GET_QUEST_QUERY, {variables: constructDefaultQuery(), notifyOnNetworkStatusChange: true}
);

const updateQuestList = useCallback((afterCursor?: string | undefined, beforeCursor?: string | undefined) => {
const defaultQuery = constructDefaultQuery(search, afterCursor, beforeCursor);
// Add filter handling
const queryWithFilter = constructFilterBasedQuery(filtersSelected , defaultQuery) as any;
refetch(queryWithFilter);
},[search, filtersSelected, constructDefaultQuery, constructFilterBasedQuery, refetch]);

useEffect(()=> {
updateQuestList();
},[updateQuestList]);

return {
data,
loading,
error,
page,
filtersSelected,
setPage,
setSearch: handleSearchChange,
setFiltersSelected: handleFilterChange,
updateQuestList
}
}
Loading

0 comments on commit aaa84f3

Please sign in to comment.