diff options
-rw-r--r-- | src/components/App.js | 12 | ||||
-rw-r--r-- | src/components/ListItem.js | 41 | ||||
-rw-r--r-- | src/components/ListView.js (renamed from src/components/List.js) | 37 | ||||
-rw-r--r-- | src/components/ScanDetail.js (renamed from src/components/ObjectComponent.js) | 97 | ||||
-rw-r--r-- | src/components/ScanView.js (renamed from src/components/ObjectView.js) | 25 | ||||
-rw-r--r-- | src/styles/main.css | 71 |
6 files changed, 163 insertions, 120 deletions
diff --git a/src/components/App.js b/src/components/App.js index cc89ca8..8eda93e 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -9,9 +9,9 @@ import { import Error from "./Error"; import Header from "./Header"; -import List from "./List"; +import ListView from "./ListView"; import Login from "./Login"; -import ObjectView from "./ObjectView"; +import ScanView from "./ScanView"; import "../styles/main.css"; @@ -63,13 +63,13 @@ class App extends React.Component { <Header clearToken={this.clearToken} /> <Switch> <Route path="/:id"> - <MakeObjectView + <MakeScanView token={this.state.token} setError={this.setError} /> </Route> <Route path="/"> - <List + <ListView token={this.state.token} setError={this.setError} /> @@ -80,9 +80,9 @@ class App extends React.Component { } } -function MakeObjectView(props) { +function MakeScanView(props) { let { id } = useParams(); - return <ObjectView id={id} token={props.token} setError={props.setError} />; + return <ScanView id={id} token={props.token} setError={props.setError} />; } export default App; diff --git a/src/components/ListItem.js b/src/components/ListItem.js new file mode 100644 index 0000000..661f8c2 --- /dev/null +++ b/src/components/ListItem.js @@ -0,0 +1,41 @@ +import React from "react"; + +import Card from "@mui/material/Card"; + +class ListItem extends React.Component { + render() { + return ( + <tr + className="list-item" + variant="outlined" + sx={{ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + paddingTop: "1em", + paddingBottom: "1em" + }} + onClick={() => (window.location = `/${this.props._id}`)} + > + <td>{this.props.timestamp_in_utc}</td> + <td> + {this.props.ip}:{this.props.port} + </td> + <td>{this.props.domain}</td> + <td>{this.props.system_name}</td> + <td> + <Card + className={ + "cve" + (this.props.vulnerable ? " vulnerable" : "") + } + variant="outlined" + > + {this.props.cve} + </Card> + </td> + </tr> + ); + } +} + +export default ListItem; diff --git a/src/components/List.js b/src/components/ListView.js index acfc369..f68efe4 100644 --- a/src/components/List.js +++ b/src/components/ListView.js @@ -2,14 +2,14 @@ import React from "react"; import Pagination from "@mui/material/Pagination"; -import ObjectComponent from "./ObjectComponent"; +import ListItem from "./ListItem"; import SearchForm from "./SearchForm"; -class List extends React.Component { +class ListView extends React.Component { constructor(props) { super(props); this.state = { - objects: [], + scans: [], filter: { field: null, value: null @@ -79,7 +79,7 @@ class List extends React.Component { `Unexpected status from soc_collector: ${json.status}` ); this.setState({ - objects: json.docs + scans: json.docs }); }) .catch(e => this.props.setError(e)); @@ -118,17 +118,22 @@ class List extends React.Component { <SearchForm filter={this.filter} /> </div> </div> - <div id="main"> - {this.state.objects.map(data => { - return ( - <ObjectComponent - summary={true} - {...data} - key={data._id} - /> - ); - })} - </div> + <table id="main"> + <tbody> + {this.state.scans + .map(scan => + scan.result.map(res => ( + <ListItem + summary={true} + {...scan} + {...res} + key={scan._id + res.cve} + /> + )) + ) + .flat()} + </tbody> + </table> <div id="pagination"> <Pagination page={this.state.page} @@ -145,4 +150,4 @@ class List extends React.Component { } } -export default List; +export default ListView; diff --git a/src/components/ObjectComponent.js b/src/components/ScanDetail.js index 2ae0b6e..a5f6d16 100644 --- a/src/components/ObjectComponent.js +++ b/src/components/ScanDetail.js @@ -1,19 +1,17 @@ import React from "react"; -import Accordion from "@mui/material/Accordion"; -import AccordionDetails from "@mui/material/AccordionDetails"; -import AccordionSummary from "@mui/material/AccordionSummary"; import Alert from "@mui/material/Alert"; import Card from "@mui/material/Card"; -import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; -class ObjectComponent extends React.Component { +class ScanDetail extends React.Component { render() { return ( - <Card className="object" variant="outlined"> + <Card className="scan-detail" variant="outlined"> <div className="id"> <a href={`/${this.props._id}`}>#{this.props._id}</a> </div> + <h2>General info</h2> + <table> <tbody> <tr> @@ -40,50 +38,48 @@ class ObjectComponent extends React.Component { <td>Abuse mail</td> <td>{this.props.abuse_mail}</td> </tr> - <tr> - <td>Scan finished at</td> - <td>{this.props.timestamp_in_utc}</td> - </tr> </tbody> </table> + + {this.props.user_presentation.description && ( + <> + <br /> + <Alert severity="info"> + {this.props.user_presentation.description} + </Alert> + </> + )} + + <h2>Custom info</h2> <Details {...this.props} /> + + <h2>Latest scan | {this.props.timestamp_in_utc}</h2> + <div id="cves"> + {this.props.result + .sort((a, b) => (a.vulnerable ? -1 : 1)) + .map(cve => ( + <CVE {...cve} /> + ))} + </div> </Card> ); } } function Details(props) { - let content = ( + return ( <> - {props.user_presentation.description && ( - <Alert severity="info" sx={{ marginTop: "1em" }}> - {props.user_presentation.description} - </Alert> - )} <UserPresentation description={props.user_presentation.description} data={props.user_presentation.data} /> </> ); - if (props.summary) { - return ( - <div> - <Accordion elevation={0} disableGutters={true}> - <AccordionSummary - expandIcon={<ExpandMoreIcon fontSize="small" />} - ></AccordionSummary> - <AccordionDetails>{content}</AccordionDetails> - </Accordion> - </div> - ); - } - return content; } function UserPresentation(props) { return ( - <div className="user-presentation" style={{ marginTop: "2em" }}> + <table className="user-presentation"> {Object.entries(props.data).map( ([key, { data, display_name, description }]) => ( <UserPresentationElement @@ -94,42 +90,29 @@ function UserPresentation(props) { /> ) )} - </div> + </table> ); } function UserPresentationElement(props) { return ( - <Card - className="user-presentation-element" - variant="outlined" - sx={{ padding: "1em", marginTop: "1em" }} - > - <b>{props.display_name}</b>: {props.data.toString()} - {props.description && ( - <Alert severity="info" sx={{ marginTop: "0.5em" }}> - {props.description} - </Alert> - )} - </Card> + <tr> + <td>{props.display_name}</td> + <td>{props.data.toString()}</td> + <td style={{ fontStyle: "italic" }}>{props.description}</td> + </tr> ); } -function GenericTable(props) { +function CVE(props) { return ( - <table> - <tbody> - {Object.entries(props.data).map(([key, value]) => { - return ( - <tr key={key}> - <td>{key}</td> - <td>{value}</td> - </tr> - ); - })} - </tbody> - </table> + <Card + className={"cve" + (props.vulnerable ? " vulnerable" : "")} + variant="outlined" + > + {props.cve} + </Card> ); } -export default ObjectComponent; +export default ScanDetail; diff --git a/src/components/ObjectView.js b/src/components/ScanView.js index 76479c2..aefd287 100644 --- a/src/components/ObjectView.js +++ b/src/components/ScanView.js @@ -1,8 +1,8 @@ import React from "react"; -import ObjectComponent from "./ObjectComponent"; +import ScanDetail from "./ScanDetail"; -class ObjectView extends React.Component { +class ScanView extends React.Component { constructor(props) { super(props); this.state = { @@ -17,11 +17,14 @@ class ObjectView extends React.Component { } getData() { - fetch(`${window.injectedEnv.COLLECTOR_URL}/sc/v0/get/${this.props.id}`, { - headers: { - Authorization: "Bearer " + this.props.token + fetch( + `${window.injectedEnv.COLLECTOR_URL}/sc/v0/get/${this.props.id}`, + { + headers: { + Authorization: "Bearer " + this.props.token + } } - }) + ) // TODO: Look at `status` or return code or both? .then(resp => { if (resp.status !== 200) @@ -43,14 +46,10 @@ class ObjectView extends React.Component { } render() { - return ( - <div id="object-view"> - {this.state.object === null ? null : ( - <ObjectComponent {...this.state.object} /> - )} - </div> + return this.state.object === null ? null : ( + <ScanDetail {...this.state.object} /> ); } } -export default ObjectView; +export default ScanView; diff --git a/src/styles/main.css b/src/styles/main.css index 606c6d2..0b01a70 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -1,3 +1,5 @@ +/* App */ + body { background: #fff; font-size: 14px; @@ -53,45 +55,39 @@ a:visited { color: #9c9c9c; } -/* Object */ +/* ScanView */ -.object { +.scan-detail { padding: 2em; margin: 2em; - width: 40em; + width: 50em; margin-left: auto; margin-right: auto; } -.object.good { - background-color: green; -} - -.object.bad { - background-color: red; -} - -.object .id { +.scan-detail .id { float: right; font-family: monospace; } -.object td { +.scan-detail td { padding-right: 2em; } -.object .MuiAccordionSummary-content { - display: none !important; -} - -.object .MuiAccordion-root { - margin-top: 2em !important; +.scan-detail .cve { + background-color: #c6ff85; + border: 3px solid #62b800; + padding: 0.5em; + margin-top: 0.5em; + text-align: center; } -.object .MuiAccordionSummary-root { +.scan-detail .cve.vulnerable { + background-color: #ff8585; + border: 3px solid #f74343; } -/* List */ +/* ListView */ #list-container > #controls { display: flex; @@ -109,13 +105,32 @@ a:visited { display: flex; } -#list-container > #main > .MuiCard-root:nth-child(odd), -#list-container > #main > .MuiCard-root:nth-child(odd) .MuiAccordion-root, -#list-container - > #main - > .MuiCard-root:nth-child(odd) - .user-presentation-element { - background-color: #fcfcfc; +#list-container > #main { + width: 80em; + margin-left: auto; + margin-right: auto; + border-collapse: collapse; +} + +.list-item td { + padding-left: 2em; + padding-right: 2em; + margin: 0; + border-top: 1px solid grey; + border-bottom: 1px solid grey; +} + +.list-item .cve { + background-color: #c6ff85; + border: 3px solid #62b800; + padding: 0.5em; + margin: 0.5em; + text-align: center; +} + +.list-item .cve.vulnerable { + background-color: #ff8585; + border: 3px solid #f74343; } /* Login */ |