Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

Node icons color bugfix #171

Merged
merged 10 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"**/*.drawio": true
},
"eslint.nodePath": ".yarn/sdks",
"prettier.prettierPath": ".yarn/sdks/prettier/index.js",
"prettier.prettierPath": "./node_modules/prettier",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
Expand Down
5 changes: 4 additions & 1 deletion applications/client/src/store/campaign/campaign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ export class CampaignStore extends ExtendedModel(() => ({
const parents = Array.from(this.appStore?.graphqlStore.hosts.values() || [], (host) => ({
id: host.id,
name: host.computedName,
className: nodeColor[host.meta[0]?.maybeCurrent?.color || 'default'].className,
className:
nodeColor[
(host.cobaltStrikeServer ? host.server?.meta?.current?.color : host.meta[0]?.maybeCurrent?.color) || 'default'
].className,
shape: host.meta[0]?.maybeCurrent?.shape,
}));
if (nodes.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { types, prop, tProp, Model, Ref, idProp } from 'mobx-keystone';
import { QueryBuilder } from 'mk-gql';
import type { BeaconType } from './BeaconTypeEnum';
import type { LogEntryModel } from './LogEntryModel';
import type { NodeColors } from './NodeColorsEnum';
import type { Shapes } from './ShapesEnum';

import { LogEntryModelSelector, logEntryModelPrimitives } from './LogEntryModel';
Expand All @@ -25,7 +26,7 @@ type Refs = {
export class BeaconMetaModelBase extends Model({
__typename: tProp('BeaconMeta'),
/** The color of the node */
color: prop<string | null>().withSetter(),
color: prop<NodeColors | null>().withSetter(),
/** The time that the last command was run */
endTime: prop<any | null>().withSetter(),
id: prop<string>().withSetter(),
Expand Down
3 changes: 2 additions & 1 deletion applications/client/src/store/graphql/HostMetaModel.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { types, prop, tProp, Model, Ref, idProp } from 'mobx-keystone';
import { QueryBuilder } from 'mk-gql';
import type { NodeColors } from './NodeColorsEnum';
import type { Shapes } from './ShapesEnum';

/**
Expand All @@ -14,7 +15,7 @@ import type { Shapes } from './ShapesEnum';
export class HostMetaModelBase extends Model({
__typename: tProp('HostMeta'),
/** The color of the node */
color: prop<string | null>().withSetter(),
color: prop<NodeColors | null>().withSetter(),
id: prop<string>().withSetter(),
ip: prop<string | null>().withSetter(),
os: prop<string | null>().withSetter(),
Expand Down
31 changes: 31 additions & 0 deletions applications/client/src/store/graphql/NodeColorsEnum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* This is a mk-gql generated file, don't modify it manually */
/* eslint-disable */
/* tslint:disable */
// @ts-nocheck
import { types, prop, tProp, Model, Ref } from 'mobx-keystone';

/**
* Typescript enum
*/

export enum NodeColors {
default = 'default',
forest = 'forest',
gold = 'gold',
green = 'green',
indigo = 'indigo',
lime = 'lime',
orange = 'orange',
red = 'red',
rose = 'rose',
turquoise = 'turquoise',
vermilion = 'vermilion',
violet = 'violet',
}

/**
* NodeColors
*
* The color of the node
*/
export const NodeColorsEnumType = types.enum(NodeColors);
13 changes: 7 additions & 6 deletions applications/client/src/store/graphql/RootStore.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import type { FileFlag } from './FileFlagEnum';
import type { GenerationType } from './GenerationTypeEnum';
import type { LogType } from './LogTypeEnum';
import type { MitreTechniques } from './MitreTechniquesEnum';
import type { NodeColors } from './NodeColorsEnum';
import type { ParsingStatus } from './ParsingStatusEnum';
import type { ServerDelineationTypes } from './ServerDelineationTypesEnum';
import type { ServerType } from './ServerTypeEnum';
Expand Down Expand Up @@ -1184,7 +1185,7 @@ export class RootStoreBase extends ExtendedModel(
beaconTimeOfDeath?: any;
beaconType?: BeaconType;
campaignId: string;
color?: string;
color?: NodeColors;
shape?: Shapes;
},
resultSelector:
Expand All @@ -1193,7 +1194,7 @@ export class RootStoreBase extends ExtendedModel(
optimisticUpdate?: () => void
) {
return this.mutate<{ updateBeaconMetadata: BeaconModel }>(
`mutation updateBeaconMetadata($beaconDisplayName: String, $beaconId: String!, $beaconTimeOfDeath: DateTime, $beaconType: BeaconType, $campaignId: String!, $color: String, $shape: Shapes) { updateBeaconMetadata(beaconDisplayName: $beaconDisplayName, beaconId: $beaconId, beaconTimeOfDeath: $beaconTimeOfDeath, beaconType: $beaconType, campaignId: $campaignId, color: $color, shape: $shape) {
`mutation updateBeaconMetadata($beaconDisplayName: String, $beaconId: String!, $beaconTimeOfDeath: DateTime, $beaconType: BeaconType, $campaignId: String!, $color: NodeColors, $shape: Shapes) { updateBeaconMetadata(beaconDisplayName: $beaconDisplayName, beaconId: $beaconId, beaconTimeOfDeath: $beaconTimeOfDeath, beaconType: $beaconType, campaignId: $campaignId, color: $color, shape: $shape) {
${typeof resultSelector === 'function' ? resultSelector(BeaconModelSelector).toString() : resultSelector}
} }`,
variables,
Expand All @@ -1202,14 +1203,14 @@ export class RootStoreBase extends ExtendedModel(
}
// Update existing Host Display Name
@modelAction mutateUpdateHostMetadata(
variables: { campaignId: string; color?: string; hostDisplayName?: string; hostId: string; shape?: Shapes },
variables: { campaignId: string; color?: NodeColors; hostDisplayName?: string; hostId: string; shape?: Shapes },
resultSelector:
| string
| ((qb: typeof HostModelSelector) => typeof HostModelSelector) = hostModelPrimitives.toString(),
optimisticUpdate?: () => void
) {
return this.mutate<{ updateHostMetadata: HostModel }>(
`mutation updateHostMetadata($campaignId: String!, $color: String, $hostDisplayName: String, $hostId: String!, $shape: Shapes) { updateHostMetadata(campaignId: $campaignId, color: $color, hostDisplayName: $hostDisplayName, hostId: $hostId, shape: $shape) {
`mutation updateHostMetadata($campaignId: String!, $color: NodeColors, $hostDisplayName: String, $hostId: String!, $shape: Shapes) { updateHostMetadata(campaignId: $campaignId, color: $color, hostDisplayName: $hostDisplayName, hostId: $hostId, shape: $shape) {
${typeof resultSelector === 'function' ? resultSelector(HostModelSelector).toString() : resultSelector}
} }`,
variables,
Expand All @@ -1220,7 +1221,7 @@ export class RootStoreBase extends ExtendedModel(
@modelAction mutateUpdateServerMetadata(
variables: {
campaignId: string;
color?: string;
color?: NodeColors;
serverDisplayName?: string;
serverId: string;
serverType?: ServerType;
Expand All @@ -1232,7 +1233,7 @@ export class RootStoreBase extends ExtendedModel(
optimisticUpdate?: () => void
) {
return this.mutate<{ updateServerMetadata: ServerModel }>(
`mutation updateServerMetadata($campaignId: String!, $color: String, $serverDisplayName: String, $serverId: String!, $serverType: ServerType, $shape: Shapes) { updateServerMetadata(campaignId: $campaignId, color: $color, serverDisplayName: $serverDisplayName, serverId: $serverId, serverType: $serverType, shape: $shape) {
`mutation updateServerMetadata($campaignId: String!, $color: NodeColors, $serverDisplayName: String, $serverId: String!, $serverType: ServerType, $shape: Shapes) { updateServerMetadata(campaignId: $campaignId, color: $color, serverDisplayName: $serverDisplayName, serverId: $serverId, serverType: $serverType, shape: $shape) {
${typeof resultSelector === 'function' ? resultSelector(ServerModelSelector).toString() : resultSelector}
} }`,
variables,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { types, prop, tProp, Model, Ref, idProp } from 'mobx-keystone';
import { QueryBuilder } from 'mk-gql';
import type { NodeColors } from './NodeColorsEnum';
import type { ServerType } from './ServerTypeEnum';
import type { Shapes } from './ShapesEnum';

Expand All @@ -15,7 +16,7 @@ import type { Shapes } from './ShapesEnum';
export class ServerMetaModelBase extends Model({
__typename: tProp('ServerMeta'),
/** The color of the node */
color: prop<string | null>().withSetter(),
color: prop<NodeColors | null>().withSetter(),
id: prop<string>().withSetter(),
shape: prop<Shapes | null>().withSetter(),
type: prop<ServerType>().withSetter(),
Expand Down
1 change: 1 addition & 0 deletions applications/client/src/store/graphql/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export * from './LinkModel';
export * from './LogEntryModel';
export * from './LogTypeEnum';
export * from './MitreTechniquesEnum';
export * from './NodeColorsEnum';
export * from './NonHidableEntitiesModel';
export * from './OperatorModel';
export * from './ParserInfoModel';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,11 @@ export const BeaconRow = observer<BeaconRowProps>(({ beacon, ...props }) => {
{store.settings.momentTz(beacon.maxTime)?.format(dateShortFormat)}
</RowTime>
<RowTitle className={skeletonClass}>
<NodeIcon type="beacon" shape="circle" color="default" />
{/* <NodeIcon type="beacon" shape="triangleUp" color="red" />
<NodeIcon type="beacon" shape="triangleDown" color="rose" />
<NodeIcon type="beacon" shape="diamond" color="indigo" />
<NodeIcon type="beacon" shape="hexagonDown" color="turquoise" />
<NodeIcon type="beacon" shape="square" color="forest" />
<NodeIcon type="beacon" shape="pentagonDown" color="lime" />
<NodeIcon type="beacon" shape="pentagonUp" color="gold" />
<NodeIcon type="beacon" shape="hexagonUp" color="orange" /> */}
<NodeIcon
type="beacon"
shape={beacon.meta?.[0]?.current?.shape || undefined}
color={beacon.meta?.[0]?.current?.color || undefined}
/>
<Txt cy-test="beacon-display-name" normal muted>
{beacon?.computedName || `${beacon.server?.computedName}`}
</Txt>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,14 @@ export const HostOrServerRow = observer<HostOrServerRowProps>(({ host, ...props
{host.maxTime ? store.settings.momentTz(host.maxTime)?.format(dateShortFormat) : dateShortPlaceholder}
</RowTime>
<RowTitle>
<NodeIcon type={host.cobaltStrikeServer ? 'server' : 'host'} color="default" />
<NodeIcon
type={host.cobaltStrikeServer ? 'server' : 'host'}
color={
host.cobaltStrikeServer
? host.server?.meta?.current?.color || undefined
: host.meta?.[0]?.current?.color || undefined
}
/>
{host.cobaltStrikeServer && <Txt muted>Server:</Txt>}
<Txt cy-test="hostName" bold={!!host.cobaltStrikeServer}>
{host.computedName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export const ServerMeta = observer((props) => {
}
} else if (args.key === 'color') {
store.campaign.graph?.updateNodeVisual({
nodeId: data.updateServerMetadata.id,
// Safer to use server.serverHost.id instead of data.updateServerMetadata.name, to cover Brute Ratel data nodeId difference at least for now.
nodeId: server?.serverHost?.id || data.updateServerMetadata.name,
className: nodeColor[state.metaDraft.originalData.color].className,
shape: 'hexagonUp',
});
Expand Down
22 changes: 19 additions & 3 deletions applications/client/src/views/Campaign/Explore/Panels/Panels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ export const sortOptions: Record<Tabs, SortOption[]> = {
export const InfoPanelTabs = {
[InfoType.BEACON]: {
title: (store: AppStore) => (
<PanelHeader nodeIconProps={{ type: 'beacon' }}>
<PanelHeader
nodeIconProps={{
type: 'beacon',
shape: store.campaign?.interactionState.selectedBeacon?.current?.meta?.[0]?.current?.shape || undefined,
color: store.campaign?.interactionState.selectedBeacon?.current?.meta?.[0]?.current?.color || undefined,
}}
>
{store.campaign?.interactionState.selectedBeacon?.current?.computedName}
</PanelHeader>
),
Expand All @@ -119,7 +125,12 @@ export const InfoPanelTabs = {
},
[InfoType.SERVER]: {
title: (store: AppStore) => (
<PanelHeader nodeIconProps={{ type: 'server' }}>
<PanelHeader
nodeIconProps={{
type: 'server',
color: store.campaign?.interactionState.selectedServer?.current?.meta?.current?.color || undefined,
}}
>
{store.campaign?.interactionState.selectedServer?.current?.computedName}
</PanelHeader>
),
Expand All @@ -132,7 +143,12 @@ export const InfoPanelTabs = {
},
[InfoType.HOST]: {
title: (store: AppStore) => (
<PanelHeader nodeIconProps={{ type: 'host' }}>
<PanelHeader
nodeIconProps={{
type: 'host',
color: store.campaign?.interactionState.selectedHost?.current?.meta?.[0]?.current?.color || undefined,
}}
>
{store.campaign?.interactionState.selectedHost?.current?.computedName}
</PanelHeader>
),
Expand Down
28 changes: 22 additions & 6 deletions applications/server/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ enum BeaconLineType {
"""Data derived from the Beacon metadata line"""
type BeaconMeta {
"""The color of the node"""
color: String
color: NodeColors

"""The time that the last command was run"""
endTime: DateTime
Expand Down Expand Up @@ -223,7 +223,7 @@ type Host {

type HostMeta {
"""The color of the node"""
color: String
color: NodeColors
id: String!
ip: String
os: String
Expand Down Expand Up @@ -377,13 +377,29 @@ type Mutation {
updateAnnotation(annotationId: String!, campaignId: String!, favorite: Boolean, tags: [String!]!, text: String!, user: String!): Annotation!

"""Update existing Beacon Metadata"""
updateBeaconMetadata(beaconDisplayName: String, beaconId: String!, beaconTimeOfDeath: DateTime, beaconType: BeaconType, campaignId: String!, color: String, shape: Shapes): Beacon!
updateBeaconMetadata(beaconDisplayName: String, beaconId: String!, beaconTimeOfDeath: DateTime, beaconType: BeaconType, campaignId: String!, color: NodeColors, shape: Shapes): Beacon!

"""Update existing Host Display Name"""
updateHostMetadata(campaignId: String!, color: String, hostDisplayName: String, hostId: String!, shape: Shapes): Host!
updateHostMetadata(campaignId: String!, color: NodeColors, hostDisplayName: String, hostId: String!, shape: Shapes): Host!

"""Update existing Server name"""
updateServerMetadata(campaignId: String!, color: String, serverDisplayName: String, serverId: String!, serverType: ServerType, shape: Shapes): Server!
updateServerMetadata(campaignId: String!, color: NodeColors, serverDisplayName: String, serverId: String!, serverType: ServerType, shape: Shapes): Server!
}

"""The color of the node"""
enum NodeColors {
default
forest
gold
green
indigo
lime
orange
red
rose
turquoise
vermilion
violet
}

type NonHidableEntities {
Expand Down Expand Up @@ -581,7 +597,7 @@ enum ServerDelineationTypes {

type ServerMeta {
"""The color of the node"""
color: String
color: NodeColors
id: String!
shape: Shapes
type: ServerType!
Expand Down
4 changes: 2 additions & 2 deletions applications/server/src/store/beacon-resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Arg, Authorized, Ctx, Query, Resolver, Mutation } from 'type-graphql';
import { Beacon, BeaconType, Shapes } from '@redeye/models';
import { Beacon, BeaconType, Shapes, NodeColors } from '@redeye/models';
import { ensureTreeHidden } from './utils/hidden-entities-helper';
import { connectToProjectEmOrFail } from './utils/project-db';
import type { Relation } from './utils/relation-path';
Expand Down Expand Up @@ -31,7 +31,7 @@ export class BeaconResolvers {
@Arg('beaconTimeOfDeath', () => Date, { nullable: true }) beaconTimeOfDeath?: Date,
@Arg('beaconType', () => BeaconType, { nullable: true }) beaconType?: BeaconType,
@Arg('shape', () => Shapes, { nullable: true }) shape?: Shapes,
@Arg('color', () => String, { nullable: true }) color?: string
@Arg('color', () => NodeColors, { nullable: true }) color?: NodeColors
): Promise<Beacon> {
const em = await connectToProjectEmOrFail(campaignId, ctx);
const beacon = await em.findOneOrFail(Beacon, beaconId, { populate: relationPaths });
Expand Down
4 changes: 2 additions & 2 deletions applications/server/src/store/host-resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Arg, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql';
import { Beacon, Host, Shapes } from '@redeye/models';
import { Beacon, Host, NodeColors, Shapes } from '@redeye/models';
import { defaultHidden, ensureTreeHidden } from './utils/hidden-entities-helper';
import { connectToProjectEmOrFail } from './utils/project-db';
import type { Relation } from './utils/relation-path';
Expand Down Expand Up @@ -31,7 +31,7 @@ export class HostResolvers {
@Arg('campaignId', () => String) campaignId: string,
@Arg('hostDisplayName', () => String, { nullable: true }) hostDisplayName?: string,
@Arg('shape', () => Shapes, { nullable: true }) shape?: Shapes,
@Arg('color', () => String, { nullable: true }) color?: string,
@Arg('color', () => NodeColors, { nullable: true }) color?: NodeColors,
@RelationPath() relationPaths?: Relation<Host>
): Promise<Host> {
const em = await connectToProjectEmOrFail(campaignId, ctx);
Expand Down
4 changes: 2 additions & 2 deletions applications/server/src/store/server-resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Arg, Resolver, Query, Authorized, Ctx, Mutation } from 'type-graphql';
import { Beacon, Campaign, Host, GlobalOperator, Server, ServerType, Shapes } from '@redeye/models';
import { Beacon, Campaign, Host, GlobalOperator, Server, ServerType, Shapes, NodeColors } from '@redeye/models';
import { connectToProjectEmOrFail, getMainEmOrFail } from './utils/project-db';
import { RelationPath } from './utils/relation-path';
import type { Relation } from './utils/relation-path';
Expand Down Expand Up @@ -131,7 +131,7 @@ export class ServerResolvers {
@Arg('serverDisplayName', () => String, { nullable: true }) serverDisplayName?: string,
@Arg('serverType', () => ServerType, { nullable: true }) serverType?: ServerType,
@Arg('shape', () => Shapes, { nullable: true }) shape?: Shapes,
@Arg('color', () => String, { nullable: true }) color?: string
@Arg('color', () => NodeColors, { nullable: true }) color?: NodeColors
): Promise<Server> {
const em = await connectToProjectEmOrFail(campaignId, ctx);
const server = await em.findOneOrFail(Server, serverId, { populate: relationPaths });
Expand Down
6 changes: 3 additions & 3 deletions packages/models/src/projectModels/BeaconMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Field, Int, ObjectType, registerEnumType } from 'type-graphql';
import { randomUUID } from 'crypto';
import { Beacon } from './Beacon';
import { LogEntry } from './LogEntry';
import { Shapes } from './shared';
import { NodeColors, Shapes } from './shared';

export enum BeaconType {
http = 'http',
Expand Down Expand Up @@ -73,9 +73,9 @@ export class BeaconMeta {
@Property({ type: 'string' })
shape: Shapes = Shapes.circle;

@Field(() => String, { nullable: true, description: 'The color of the node' })
@Field(() => NodeColors, { nullable: true, description: 'The color of the node' })
@Property({ type: 'string', nullable: true })
color?: string;
color?: NodeColors;

// This is likely to be nullable in future due to different ways we have to extract this data in other C2 tools
@Field(() => LogEntry, { description: 'The log line from which the BeaconMeta was extracted', nullable: true })
Expand Down
Loading
Loading