diff --git a/.vscode/settings.json b/.vscode/settings.json index 2469c7a2..ee4fc391 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" diff --git a/applications/client/src/store/campaign/campaign.ts b/applications/client/src/store/campaign/campaign.ts index e990a9bd..dd994324 100644 --- a/applications/client/src/store/campaign/campaign.ts +++ b/applications/client/src/store/campaign/campaign.ts @@ -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) { diff --git a/applications/client/src/store/graphql/BeaconMetaModel.base.ts b/applications/client/src/store/graphql/BeaconMetaModel.base.ts index e09240aa..17f85242 100644 --- a/applications/client/src/store/graphql/BeaconMetaModel.base.ts +++ b/applications/client/src/store/graphql/BeaconMetaModel.base.ts @@ -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'; @@ -25,7 +26,7 @@ type Refs = { export class BeaconMetaModelBase extends Model({ __typename: tProp('BeaconMeta'), /** The color of the node */ - color: prop().withSetter(), + color: prop().withSetter(), /** The time that the last command was run */ endTime: prop().withSetter(), id: prop().withSetter(), diff --git a/applications/client/src/store/graphql/HostMetaModel.base.ts b/applications/client/src/store/graphql/HostMetaModel.base.ts index e66f7879..059fa2c6 100644 --- a/applications/client/src/store/graphql/HostMetaModel.base.ts +++ b/applications/client/src/store/graphql/HostMetaModel.base.ts @@ -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'; /** @@ -14,7 +15,7 @@ import type { Shapes } from './ShapesEnum'; export class HostMetaModelBase extends Model({ __typename: tProp('HostMeta'), /** The color of the node */ - color: prop().withSetter(), + color: prop().withSetter(), id: prop().withSetter(), ip: prop().withSetter(), os: prop().withSetter(), diff --git a/applications/client/src/store/graphql/NodeColorsEnum.ts b/applications/client/src/store/graphql/NodeColorsEnum.ts new file mode 100644 index 00000000..770e842a --- /dev/null +++ b/applications/client/src/store/graphql/NodeColorsEnum.ts @@ -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); diff --git a/applications/client/src/store/graphql/RootStore.base.ts b/applications/client/src/store/graphql/RootStore.base.ts index 6d4d7ade..88b4f4a8 100644 --- a/applications/client/src/store/graphql/RootStore.base.ts +++ b/applications/client/src/store/graphql/RootStore.base.ts @@ -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'; @@ -1184,7 +1185,7 @@ export class RootStoreBase extends ExtendedModel( beaconTimeOfDeath?: any; beaconType?: BeaconType; campaignId: string; - color?: string; + color?: NodeColors; shape?: Shapes; }, resultSelector: @@ -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, @@ -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, @@ -1220,7 +1221,7 @@ export class RootStoreBase extends ExtendedModel( @modelAction mutateUpdateServerMetadata( variables: { campaignId: string; - color?: string; + color?: NodeColors; serverDisplayName?: string; serverId: string; serverType?: ServerType; @@ -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, diff --git a/applications/client/src/store/graphql/ServerMetaModel.base.ts b/applications/client/src/store/graphql/ServerMetaModel.base.ts index f1490a1a..119fb457 100644 --- a/applications/client/src/store/graphql/ServerMetaModel.base.ts +++ b/applications/client/src/store/graphql/ServerMetaModel.base.ts @@ -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'; @@ -15,7 +16,7 @@ import type { Shapes } from './ShapesEnum'; export class ServerMetaModelBase extends Model({ __typename: tProp('ServerMeta'), /** The color of the node */ - color: prop().withSetter(), + color: prop().withSetter(), id: prop().withSetter(), shape: prop().withSetter(), type: prop().withSetter(), diff --git a/applications/client/src/store/graphql/root.ts b/applications/client/src/store/graphql/root.ts index fd85f52c..db19941a 100644 --- a/applications/client/src/store/graphql/root.ts +++ b/applications/client/src/store/graphql/root.ts @@ -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'; diff --git a/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx b/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx index fc139aad..b412e5b9 100644 --- a/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx +++ b/applications/client/src/views/Campaign/Explore/Panels/Beacon/BeaconRow.tsx @@ -126,15 +126,11 @@ export const BeaconRow = observer(({ beacon, ...props }) => { {store.settings.momentTz(beacon.maxTime)?.format(dateShortFormat)} - - {/* - - - - - - - */} + {beacon?.computedName || `${beacon.server?.computedName}`} diff --git a/applications/client/src/views/Campaign/Explore/Panels/Host/HostOrServerRow.tsx b/applications/client/src/views/Campaign/Explore/Panels/Host/HostOrServerRow.tsx index 1700a8c1..43bae932 100644 --- a/applications/client/src/views/Campaign/Explore/Panels/Host/HostOrServerRow.tsx +++ b/applications/client/src/views/Campaign/Explore/Panels/Host/HostOrServerRow.tsx @@ -158,7 +158,14 @@ export const HostOrServerRow = observer(({ host, ...props {host.maxTime ? store.settings.momentTz(host.maxTime)?.format(dateShortFormat) : dateShortPlaceholder} - + {host.cobaltStrikeServer && Server:} {host.computedName} diff --git a/applications/client/src/views/Campaign/Explore/Panels/Meta/ServerMeta.tsx b/applications/client/src/views/Campaign/Explore/Panels/Meta/ServerMeta.tsx index 8d3f35df..07ebc93d 100644 --- a/applications/client/src/views/Campaign/Explore/Panels/Meta/ServerMeta.tsx +++ b/applications/client/src/views/Campaign/Explore/Panels/Meta/ServerMeta.tsx @@ -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', }); diff --git a/applications/client/src/views/Campaign/Explore/Panels/Panels.tsx b/applications/client/src/views/Campaign/Explore/Panels/Panels.tsx index 5ad71485..22ebb518 100644 --- a/applications/client/src/views/Campaign/Explore/Panels/Panels.tsx +++ b/applications/client/src/views/Campaign/Explore/Panels/Panels.tsx @@ -93,7 +93,13 @@ export const sortOptions: Record = { export const InfoPanelTabs = { [InfoType.BEACON]: { title: (store: AppStore) => ( - + {store.campaign?.interactionState.selectedBeacon?.current?.computedName} ), @@ -119,7 +125,12 @@ export const InfoPanelTabs = { }, [InfoType.SERVER]: { title: (store: AppStore) => ( - + {store.campaign?.interactionState.selectedServer?.current?.computedName} ), @@ -132,7 +143,12 @@ export const InfoPanelTabs = { }, [InfoType.HOST]: { title: (store: AppStore) => ( - + {store.campaign?.interactionState.selectedHost?.current?.computedName} ), diff --git a/applications/server/schema.graphql b/applications/server/schema.graphql index 786d04fa..c7470026 100644 --- a/applications/server/schema.graphql +++ b/applications/server/schema.graphql @@ -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 @@ -223,7 +223,7 @@ type Host { type HostMeta { """The color of the node""" - color: String + color: NodeColors id: String! ip: String os: String @@ -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 { @@ -581,7 +597,7 @@ enum ServerDelineationTypes { type ServerMeta { """The color of the node""" - color: String + color: NodeColors id: String! shape: Shapes type: ServerType! diff --git a/applications/server/src/store/beacon-resolvers.ts b/applications/server/src/store/beacon-resolvers.ts index b9c7cf5d..9a3c7b72 100644 --- a/applications/server/src/store/beacon-resolvers.ts +++ b/applications/server/src/store/beacon-resolvers.ts @@ -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'; @@ -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 { const em = await connectToProjectEmOrFail(campaignId, ctx); const beacon = await em.findOneOrFail(Beacon, beaconId, { populate: relationPaths }); diff --git a/applications/server/src/store/host-resolvers.ts b/applications/server/src/store/host-resolvers.ts index 618e9097..3cd27e74 100644 --- a/applications/server/src/store/host-resolvers.ts +++ b/applications/server/src/store/host-resolvers.ts @@ -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'; @@ -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 ): Promise { const em = await connectToProjectEmOrFail(campaignId, ctx); diff --git a/applications/server/src/store/server-resolvers.ts b/applications/server/src/store/server-resolvers.ts index b0b33bb6..1898d00a 100644 --- a/applications/server/src/store/server-resolvers.ts +++ b/applications/server/src/store/server-resolvers.ts @@ -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'; @@ -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 { const em = await connectToProjectEmOrFail(campaignId, ctx); const server = await em.findOneOrFail(Server, serverId, { populate: relationPaths }); diff --git a/packages/models/src/projectModels/BeaconMeta.ts b/packages/models/src/projectModels/BeaconMeta.ts index 8ea661ea..4b606702 100644 --- a/packages/models/src/projectModels/BeaconMeta.ts +++ b/packages/models/src/projectModels/BeaconMeta.ts @@ -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', @@ -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 }) diff --git a/packages/models/src/projectModels/HostMeta.ts b/packages/models/src/projectModels/HostMeta.ts index f5655e7e..6c913239 100644 --- a/packages/models/src/projectModels/HostMeta.ts +++ b/packages/models/src/projectModels/HostMeta.ts @@ -3,7 +3,7 @@ import { Property, PrimaryKey, Entity, ManyToOne, Unique } from '@mikro-orm/core import { Field, ObjectType } from 'type-graphql'; import { randomUUID } from 'crypto'; import { Host } from './Host'; -import { Shapes } from './shared'; +import { NodeColors, Shapes } from './shared'; @ObjectType() @Entity() @@ -41,9 +41,9 @@ export class HostMeta { @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; /** * Relationships diff --git a/packages/models/src/projectModels/ServerMeta.ts b/packages/models/src/projectModels/ServerMeta.ts index 5c39bbf2..15c19852 100644 --- a/packages/models/src/projectModels/ServerMeta.ts +++ b/packages/models/src/projectModels/ServerMeta.ts @@ -3,7 +3,7 @@ import { Entity, Enum, OneToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { randomUUID } from 'crypto'; import { Field, ObjectType, registerEnumType } from 'type-graphql'; import { Server } from './Server'; -import { Shapes } from './shared'; +import { NodeColors, Shapes } from './shared'; export enum ServerType { http = 'http', @@ -37,9 +37,9 @@ export class ServerMeta { @Property({ type: 'string' }) shape: Shapes = Shapes.hexagonUp; - @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; /** * Relationships diff --git a/packages/models/src/projectModels/index.ts b/packages/models/src/projectModels/index.ts index 465defa3..470dd116 100644 --- a/packages/models/src/projectModels/index.ts +++ b/packages/models/src/projectModels/index.ts @@ -17,7 +17,7 @@ import { Server } from './Server'; import { ServerMeta, ServerType } from './ServerMeta'; import { Tag } from './Tag'; import { Timeline, TimelineBucket, TimelineCommandCountTuple } from './Timeline'; -import { GenerationType, Shapes } from './shared'; +import { GenerationType, Shapes, NodeColors } from './shared'; export const campaignEntities = [ Annotation, @@ -72,6 +72,7 @@ export { LogType, ServerType, Shapes, + NodeColors, MitreTechniques, mitreTechniques, }; diff --git a/packages/models/src/projectModels/shared.ts b/packages/models/src/projectModels/shared.ts index 16d3ccc1..b397bf2a 100644 --- a/packages/models/src/projectModels/shared.ts +++ b/packages/models/src/projectModels/shared.ts @@ -27,3 +27,23 @@ registerEnumType(Shapes, { name: 'Shapes', description: `The shape of the node`, }); + +export enum NodeColors { + default = 'default', + vermilion = 'vermilion', + red = 'red', + rose = 'rose', + violet = 'violet', + indigo = 'indigo', + turquoise = 'turquoise', + green = 'green', + forest = 'forest', + lime = 'lime', + gold = 'gold', + orange = 'orange', +} + +registerEnumType(NodeColors, { + name: 'NodeColors', + description: `The color of the node`, +});