|
| 1 | +import React, { Component } from 'react'; |
| 2 | +import * as PropTypes from 'prop-types'; |
| 3 | +import { Route, Routes, Link, Navigate } from 'react-router-dom'; |
| 4 | +import { graphql } from 'react-relay'; |
| 5 | +import { propOr } from 'ramda'; |
| 6 | +import * as R from 'ramda'; |
| 7 | +import Box from '@mui/material/Box'; |
| 8 | +import Tabs from '@mui/material/Tabs'; |
| 9 | +import Tab from '@mui/material/Tab'; |
| 10 | +import StixCoreObjectContentRoot from '../../common/stix_core_objects/StixCoreObjectContentRoot'; |
| 11 | +import withRouter from '../../../../utils/compat_router/withRouter'; |
| 12 | +import { QueryRenderer, requestSubscription } from '../../../../relay/environment'; |
| 13 | +import System from './System'; |
| 14 | +import SystemKnowledge from './SystemKnowledge'; |
| 15 | +import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader'; |
| 16 | +import FileManager from '../../common/files/FileManager'; |
| 17 | +import SystemPopover from './SystemPopover'; |
| 18 | +import Loader from '../../../../components/Loader'; |
| 19 | +import StixCoreObjectHistory from '../../common/stix_core_objects/StixCoreObjectHistory'; |
| 20 | +import SystemAnalysis from './SystemAnalysis'; |
| 21 | +import ErrorNotFound from '../../../../components/ErrorNotFound'; |
| 22 | +import { buildViewParamsFromUrlAndStorage, saveViewParameters } from '../../../../utils/ListParameters'; |
| 23 | +import StixCoreObjectKnowledgeBar from '../../common/stix_core_objects/StixCoreObjectKnowledgeBar'; |
| 24 | +import EntityStixSightingRelationships from '../../events/stix_sighting_relationships/EntityStixSightingRelationships'; |
| 25 | +import inject18n from '../../../../components/i18n'; |
| 26 | +import Breadcrumbs from '../../../../components/Breadcrumbs'; |
| 27 | +import { getCurrentTab, getPaddingRight } from '../../../../utils/utils'; |
| 28 | +import Security from '../../../../utils/Security'; |
| 29 | +import { KNOWLEDGE_KNUPDATE } from '../../../../utils/hooks/useGranted'; |
| 30 | +import SystemEdition from './SystemEdition'; |
| 31 | + |
| 32 | +const subscription = graphql` |
| 33 | + subscription RootSystemsSubscription($id: ID!) { |
| 34 | + stixDomainObject(id: $id) { |
| 35 | + ... on System { |
| 36 | + ...System_system |
| 37 | + ...SystemEditionContainer_system |
| 38 | + } |
| 39 | + ...FileImportViewer_entity |
| 40 | + ...FileExportViewer_entity |
| 41 | + ...FileExternalReferencesViewer_entity |
| 42 | + ...WorkbenchFileViewer_entity |
| 43 | + } |
| 44 | + } |
| 45 | +`; |
| 46 | + |
| 47 | +const systemQuery = graphql` |
| 48 | + query RootSystemQuery($id: String!) { |
| 49 | + system(id: $id) { |
| 50 | + id |
| 51 | + entity_type |
| 52 | + name |
| 53 | + x_opencti_aliases |
| 54 | + stixCoreObjectsDistribution(field: "entity_type", operation: count) { |
| 55 | + label |
| 56 | + value |
| 57 | + } |
| 58 | + ...System_system |
| 59 | + ...SystemKnowledge_system |
| 60 | + ...FileImportViewer_entity |
| 61 | + ...FileExportViewer_entity |
| 62 | + ...FileExternalReferencesViewer_entity |
| 63 | + ...WorkbenchFileViewer_entity |
| 64 | + ...StixCoreObjectContent_stixCoreObject |
| 65 | + } |
| 66 | + connectorsForImport { |
| 67 | + ...FileManager_connectorsImport |
| 68 | + } |
| 69 | + connectorsForExport { |
| 70 | + ...FileManager_connectorsExport |
| 71 | + } |
| 72 | + } |
| 73 | +`; |
| 74 | + |
| 75 | +class RootSystem extends Component { |
| 76 | + constructor(props) { |
| 77 | + super(props); |
| 78 | + const { |
| 79 | + params: { systemId }, |
| 80 | + } = props; |
| 81 | + const LOCAL_STORAGE_KEY = `system-${systemId}`; |
| 82 | + const params = buildViewParamsFromUrlAndStorage( |
| 83 | + props.navigate, |
| 84 | + props.location, |
| 85 | + LOCAL_STORAGE_KEY, |
| 86 | + ); |
| 87 | + this.state = { |
| 88 | + viewAs: propOr('knowledge', 'viewAs', params), |
| 89 | + }; |
| 90 | + this.sub = requestSubscription({ |
| 91 | + subscription, |
| 92 | + variables: { id: systemId }, |
| 93 | + }); |
| 94 | + } |
| 95 | + |
| 96 | + componentWillUnmount() { |
| 97 | + this.sub.dispose(); |
| 98 | + } |
| 99 | + |
| 100 | + saveView() { |
| 101 | + const { |
| 102 | + params: { systemId }, |
| 103 | + } = this.props; |
| 104 | + const LOCAL_STORAGE_KEY = `system-${systemId}`; |
| 105 | + saveViewParameters( |
| 106 | + this.props.navigate, |
| 107 | + this.props.location, |
| 108 | + LOCAL_STORAGE_KEY, |
| 109 | + this.state, |
| 110 | + true, |
| 111 | + ); |
| 112 | + } |
| 113 | + |
| 114 | + handleChangeViewAs(event) { |
| 115 | + this.setState({ viewAs: event.target.value }, () => this.saveView()); |
| 116 | + } |
| 117 | + |
| 118 | + render() { |
| 119 | + const { |
| 120 | + t, |
| 121 | + location, |
| 122 | + params: { systemId }, |
| 123 | + } = this.props; |
| 124 | + const { viewAs } = this.state; |
| 125 | + const link = `/dashboard/entities/systems/${systemId}/knowledge`; |
| 126 | + |
| 127 | + return ( |
| 128 | + <> |
| 129 | + <QueryRenderer |
| 130 | + query={systemQuery} |
| 131 | + variables={{ id: systemId }} |
| 132 | + render={({ props }) => { |
| 133 | + if (props) { |
| 134 | + if (props.system) { |
| 135 | + const { system } = props; |
| 136 | + const paddingRight = getPaddingRight(location.pathname, system.id, '/dashboard/entities/systems'); |
| 137 | + return ( |
| 138 | + <> |
| 139 | + <Routes> |
| 140 | + <Route |
| 141 | + path="/knowledge/*" |
| 142 | + element={viewAs === 'knowledge' && ( |
| 143 | + <StixCoreObjectKnowledgeBar |
| 144 | + stixCoreObjectLink={link} |
| 145 | + availableSections={[ |
| 146 | + 'systems', |
| 147 | + 'systems', |
| 148 | + 'threats', |
| 149 | + 'threat_actors', |
| 150 | + 'intrusion_sets', |
| 151 | + 'campaigns', |
| 152 | + 'incidents', |
| 153 | + 'malwares', |
| 154 | + 'attack_patterns', |
| 155 | + 'tools', |
| 156 | + 'observables', |
| 157 | + 'vulnerabilities', |
| 158 | + ]} |
| 159 | + stixCoreObjectsDistribution={system.stixCoreObjectsDistribution} |
| 160 | + /> |
| 161 | + )} |
| 162 | + /> |
| 163 | + </Routes> |
| 164 | + <div style={{ paddingRight }}> |
| 165 | + <Breadcrumbs variant="object" elements={[ |
| 166 | + { label: t('Entities') }, |
| 167 | + { label: t('Systems'), link: '/dashboard/entities/systems' }, |
| 168 | + { label: system.name, current: true }, |
| 169 | + ]} |
| 170 | + /> |
| 171 | + <StixDomainObjectHeader |
| 172 | + entityType="System" |
| 173 | + stixDomainObject={system} |
| 174 | + isOpenctiAlias={true} |
| 175 | + enableQuickSubscription={true} |
| 176 | + PopoverComponent={<SystemPopover />} |
| 177 | + EditComponent={( |
| 178 | + <Security needs={[KNOWLEDGE_KNUPDATE]}> |
| 179 | + <SystemEdition systemId={system.id} /> |
| 180 | + </Security> |
| 181 | + )} |
| 182 | + onViewAs={this.handleChangeViewAs.bind(this)} |
| 183 | + viewAs={viewAs} |
| 184 | + /> |
| 185 | + <Box |
| 186 | + sx={{ |
| 187 | + borderBottom: 1, |
| 188 | + borderColor: 'divider', |
| 189 | + marginBottom: 3, |
| 190 | + }} |
| 191 | + > |
| 192 | + <Tabs |
| 193 | + value={getCurrentTab(location.pathname, system.id, '/dashboard/entities/systems')} |
| 194 | + > |
| 195 | + <Tab |
| 196 | + component={Link} |
| 197 | + to={`/dashboard/entities/systems/${system.id}`} |
| 198 | + value={`/dashboard/entities/systems/${system.id}`} |
| 199 | + label={t('Overview')} |
| 200 | + /> |
| 201 | + <Tab |
| 202 | + component={Link} |
| 203 | + to={`/dashboard/entities/systems/${system.id}/knowledge/overview`} |
| 204 | + value={`/dashboard/entities/systems/${system.id}/knowledge`} |
| 205 | + label={t('Knowledge')} |
| 206 | + /> |
| 207 | + <Tab |
| 208 | + component={Link} |
| 209 | + to={`/dashboard/entities/systems/${system.id}/content`} |
| 210 | + value={`/dashboard/entities/systems/${system.id}/content`} |
| 211 | + label={t('Content')} |
| 212 | + /> |
| 213 | + <Tab |
| 214 | + component={Link} |
| 215 | + to={`/dashboard/entities/systems/${system.id}/analyses`} |
| 216 | + value={`/dashboard/entities/systems/${system.id}/analyses`} |
| 217 | + label={t('Analyses')} |
| 218 | + /> |
| 219 | + <Tab |
| 220 | + component={Link} |
| 221 | + to={`/dashboard/entities/systems/${system.id}/sightings`} |
| 222 | + value={`/dashboard/entities/systems/${system.id}/sightings`} |
| 223 | + label={t('Sightings')} |
| 224 | + /> |
| 225 | + <Tab |
| 226 | + component={Link} |
| 227 | + to={`/dashboard/entities/systems/${system.id}/files`} |
| 228 | + value={`/dashboard/entities/systems/${system.id}/files`} |
| 229 | + label={t('Data')} |
| 230 | + /> |
| 231 | + <Tab |
| 232 | + component={Link} |
| 233 | + to={`/dashboard/entities/systems/${system.id}/history`} |
| 234 | + value={`/dashboard/entities/systems/${system.id}/history`} |
| 235 | + label={t('History')} |
| 236 | + /> |
| 237 | + </Tabs> |
| 238 | + </Box> |
| 239 | + <Routes> |
| 240 | + <Route |
| 241 | + path="/" |
| 242 | + element={ |
| 243 | + <System |
| 244 | + systemData={system} |
| 245 | + viewAs={viewAs} |
| 246 | + /> |
| 247 | + } |
| 248 | + /> |
| 249 | + <Route |
| 250 | + path="/knowledge" |
| 251 | + element={ |
| 252 | + <Navigate |
| 253 | + replace={true} |
| 254 | + to={`/dashboard/entities/systems/${systemId}/knowledge/overview`} |
| 255 | + /> |
| 256 | + } |
| 257 | + /> |
| 258 | + <Route |
| 259 | + path="/knowledge/*" |
| 260 | + element={ |
| 261 | + <SystemKnowledge |
| 262 | + system={system} |
| 263 | + viewAs={viewAs} |
| 264 | + /> |
| 265 | + } |
| 266 | + /> |
| 267 | + <Route |
| 268 | + path="/content/*" |
| 269 | + element={ |
| 270 | + <StixCoreObjectContentRoot |
| 271 | + stixCoreObject={system} |
| 272 | + /> |
| 273 | + } |
| 274 | + /> |
| 275 | + <Route |
| 276 | + path="/analyses/*" |
| 277 | + element={ |
| 278 | + <SystemAnalysis |
| 279 | + system={system} |
| 280 | + viewAs={viewAs} |
| 281 | + /> |
| 282 | + } |
| 283 | + /> |
| 284 | + <Route |
| 285 | + path="/sightings" |
| 286 | + element={ |
| 287 | + <EntityStixSightingRelationships |
| 288 | + entityId={system.id} |
| 289 | + entityLink={link} |
| 290 | + noPadding={true} |
| 291 | + isTo={true} |
| 292 | + /> |
| 293 | + } |
| 294 | + /> |
| 295 | + <Route |
| 296 | + path="/files" |
| 297 | + element={ |
| 298 | + <FileManager |
| 299 | + id={systemId} |
| 300 | + connectorsImport={props.connectorsForImport} |
| 301 | + connectorsExport={props.connectorsForExport} |
| 302 | + entity={system} |
| 303 | + /> |
| 304 | + } |
| 305 | + /> |
| 306 | + <Route |
| 307 | + path="/history" |
| 308 | + element={ |
| 309 | + <StixCoreObjectHistory |
| 310 | + stixCoreObjectId={systemId} |
| 311 | + /> |
| 312 | + } |
| 313 | + /> |
| 314 | + </Routes> |
| 315 | + </div> |
| 316 | + </> |
| 317 | + ); |
| 318 | + } |
| 319 | + return <ErrorNotFound />; |
| 320 | + } |
| 321 | + return <Loader />; |
| 322 | + }} |
| 323 | + /> |
| 324 | + </> |
| 325 | + ); |
| 326 | + } |
| 327 | +} |
| 328 | + |
| 329 | +RootSystem.propTypes = { |
| 330 | + children: PropTypes.node, |
| 331 | + params: PropTypes.object, |
| 332 | +}; |
| 333 | + |
| 334 | +export default R.compose(inject18n, withRouter)(RootSystem); |
0 commit comments