diff options
Diffstat (limited to 'frontend/src/components')
-rw-r--r-- | frontend/src/components/Header.js | 28 | ||||
-rw-r--r-- | frontend/src/components/Header.scss | 17 | ||||
-rw-r--r-- | frontend/src/components/Timeline.js | 2 | ||||
-rw-r--r-- | frontend/src/components/pages/ConfigurationPage.js | 1 | ||||
-rw-r--r-- | frontend/src/components/pages/ConfigurationPage.scss | 10 | ||||
-rw-r--r-- | frontend/src/components/pages/MainPage.js | 72 | ||||
-rw-r--r-- | frontend/src/components/pages/MainPage.scss | 20 | ||||
-rw-r--r-- | frontend/src/components/pages/common.scss | 16 | ||||
-rw-r--r-- | frontend/src/components/panels/StreamsPane.js | 40 | ||||
-rw-r--r-- | frontend/src/components/panels/StreamsPane.scss | 12 |
10 files changed, 128 insertions, 90 deletions
diff --git a/frontend/src/components/Header.js b/frontend/src/components/Header.js index c46d768..4db05a5 100644 --- a/frontend/src/components/Header.js +++ b/frontend/src/components/Header.js @@ -46,19 +46,17 @@ class Header extends Component { render() { return ( - <header className="header container-fluid"> - <div className="row"> - <div className={classNames({"col-auto": this.props.configured, "col": !this.props.configured})}> - <h1 className="header-title type-wrap"> - <Link to="/"> - <span style={{whiteSpace: "pre"}} ref={(el) => { - this.el = el; - }}/> - </Link> - </h1> - </div> + <header className={classNames("header", {"configured": this.props.configured})}> + <div className="header-content"> + <h1 className="header-title type-wrap"> + <Link to="/"> + <span style={{whiteSpace: "pre"}} ref={(el) => { + this.el = el; + }}/> + </Link> + </h1> - {this.props.configured && <div className="col-auto"> + {this.props.configured && <div className="filters-bar"> <StringConnectionsFilter filterName="service_port" defaultFilterValue="all_ports" @@ -71,9 +69,9 @@ class Header extends Component { <ExitSearchFilter/> <AdvancedFilters onClick={this.props.onOpenFilters}/> </div> - </div>} + } - {this.props.configured && <div className="col"> + {this.props.configured && <div className="header-buttons"> <Link to={"/searches" + this.props.location.search}> <ButtonField variant="pink" name="searches" bordered/> @@ -91,7 +89,7 @@ class Header extends Component { <ButtonField variant="blue" name="config" bordered/> </Link> </div> - </div>} + } </div> </header> ); diff --git a/frontend/src/components/Header.scss b/frontend/src/components/Header.scss index fff28e6..c6a88b7 100644 --- a/frontend/src/components/Header.scss +++ b/frontend/src/components/Header.scss @@ -1,16 +1,18 @@ @import "../colors"; .header { - height: 80px; - padding: 15px 30px; + padding: 15px; - > .row { + .header-content { + display: flex; + width: 100%; + padding: 0 10px; background-color: $color-primary-0; } .header-title { width: 200px; - margin: 5px 0 5px -5px; + margin: 5px 0 5px 0; } .header-buttons { @@ -24,6 +26,7 @@ } .filters-bar { + flex: 1; padding: 3px 0; .filter, @@ -38,4 +41,10 @@ border-radius: 5px; } } + + @media screen and (max-width: 1530px) { + &.configured .header-title { + display: none; + } + } } diff --git a/frontend/src/components/Timeline.js b/frontend/src/components/Timeline.js index 9ecbd80..5443a3b 100644 --- a/frontend/src/components/Timeline.js +++ b/frontend/src/components/Timeline.js @@ -256,7 +256,7 @@ class Timeline extends Component { enablePanZoom={true} utc={false} onTimeRangeChanged={this.handleTimeRangeChange}> - <ChartRow height="125"> + <ChartRow height={this.props.height - 70}> <YAxis id="axis1" hideAxisLine min={this.aggregateSeries("min")} max={this.aggregateSeries("max")} width="35" type="linear" transition={300}/> diff --git a/frontend/src/components/pages/ConfigurationPage.js b/frontend/src/components/pages/ConfigurationPage.js index 8f9b68b..c8646fb 100644 --- a/frontend/src/components/pages/ConfigurationPage.js +++ b/frontend/src/components/pages/ConfigurationPage.js @@ -28,7 +28,6 @@ import TextField from "../fields/TextField"; import Header from "../Header"; import LinkPopover from "../objects/LinkPopover"; import "../panels/common.scss"; -import "./common.scss"; import "./ConfigurationPage.scss"; class ConfigurationPage extends Component { diff --git a/frontend/src/components/pages/ConfigurationPage.scss b/frontend/src/components/pages/ConfigurationPage.scss index 4254547..6ff933c 100644 --- a/frontend/src/components/pages/ConfigurationPage.scss +++ b/frontend/src/components/pages/ConfigurationPage.scss @@ -1,6 +1,7 @@ @import "../../colors"; .configuration-page { + height: 100vh; background-color: $color-primary-0; .header-title { @@ -10,16 +11,10 @@ .configuration-pane { display: flex; justify-content: center; - height: 100%; - padding-top: 100px; .section-content { - background-color: $color-primary-3; margin-top: 15px; - } - - .section-table table { - background-color: red !important; + background-color: $color-primary-3; } .section-footer { @@ -27,4 +22,3 @@ } } } - diff --git a/frontend/src/components/pages/MainPage.js b/frontend/src/components/pages/MainPage.js index c4dcd20..3bf8065 100644 --- a/frontend/src/components/pages/MainPage.js +++ b/frontend/src/components/pages/MainPage.js @@ -16,6 +16,8 @@ */ import React, {Component} from "react"; +import {ReflexContainer, ReflexElement, ReflexSplitter} from "react-reflex"; +import "react-reflex/styles.css" import {Route, Switch} from "react-router-dom"; import Filters from "../dialogs/Filters"; import Header from "../Header"; @@ -27,12 +29,22 @@ import SearchPane from "../panels/SearchPane"; import ServicesPane from "../panels/ServicesPane"; import StreamsPane from "../panels/StreamsPane"; import Timeline from "../Timeline"; -import "./common.scss"; import "./MainPage.scss"; class MainPage extends Component { - state = {}; + state = { + timelineHeight: 210 + }; + + handleTimelineResize = (e) => { + if (this.timelineTimeoutHandle) { + clearTimeout(this.timelineTimeoutHandle); + } + + this.timelineTimeoutHandle = setTimeout(() => + this.setState({timelineHeight: e.domElement.clientHeight}), 100); + }; render() { let modal; @@ -41,34 +53,42 @@ class MainPage extends Component { } return ( - <div className="page main-page"> - <div className="page-header"> - <Header onOpenFilters={() => this.setState({filterWindowOpen: true})} configured={true}/> + <ReflexContainer orientation="horizontal" className="page main-page"> + <div className="fuck-css"> + <ReflexElement className="page-header"> + <Header onOpenFilters={() => this.setState({filterWindowOpen: true})} configured={true}/> + {modal} + </ReflexElement> </div> - <div className="page-content"> - <div className="pane connections-pane"> - <Connections onSelected={(c) => this.setState({selectedConnection: c})}/> - </div> - <div className="pane details-pane"> - <Switch> - <Route path="/searches" children={<SearchPane/>}/> - <Route path="/pcaps" children={<PcapsPane/>}/> - <Route path="/rules" children={<RulesPane/>}/> - <Route path="/services" children={<ServicesPane/>}/> - <Route exact path="/connections/:id" - children={<StreamsPane connection={this.state.selectedConnection}/>}/> - <Route children={<MainPane version={this.props.version}/>}/> - </Switch> - </div> + <ReflexElement className="page-content" flex={1}> + <ReflexContainer orientation="vertical" className="page-content"> + <ReflexElement className="pane connections-pane"> + <Connections onSelected={(c) => this.setState({selectedConnection: c})}/> + </ReflexElement> - {modal} - </div> + <ReflexSplitter/> - <div className="page-footer"> - <Timeline/> - </div> - </div> + <ReflexElement className="pane details-pane"> + <Switch> + <Route path="/searches" children={<SearchPane/>}/> + <Route path="/pcaps" children={<PcapsPane/>}/> + <Route path="/rules" children={<RulesPane/>}/> + <Route path="/services" children={<ServicesPane/>}/> + <Route exact path="/connections/:id" + children={<StreamsPane connection={this.state.selectedConnection}/>}/> + <Route children={<MainPane version={this.props.version}/>}/> + </Switch> + </ReflexElement> + </ReflexContainer> + </ReflexElement> + + <ReflexSplitter propagate={true}/> + + <ReflexElement className="page-footer" onResize={this.handleTimelineResize}> + <Timeline height={this.state.timelineHeight}/> + </ReflexElement> + </ReflexContainer> ); } } diff --git a/frontend/src/components/pages/MainPage.scss b/frontend/src/components/pages/MainPage.scss index 4ca54c0..8d1fa96 100644 --- a/frontend/src/components/pages/MainPage.scss +++ b/frontend/src/components/pages/MainPage.scss @@ -1,25 +1,23 @@ @import "../../colors"; .main-page { + height: 100vh !important; + + .page-footer { + overflow: hidden !important; + min-height: 210px; + } + .page-content { - display: flex; - flex: 1; - padding: 0 15px; - background-color: $color-primary-2; + padding: 0 7.5px; .connections-pane { - flex: 1 0; margin-right: 7.5px; } .details-pane { - position: relative; - flex: 1 1; + overflow: hidden; margin-left: 7.5px; } } - - .page-footer { - flex: 0; - } } diff --git a/frontend/src/components/pages/common.scss b/frontend/src/components/pages/common.scss deleted file mode 100644 index fcf5c20..0000000 --- a/frontend/src/components/pages/common.scss +++ /dev/null @@ -1,16 +0,0 @@ -.page { - position: relative; - display: flex; - flex-direction: column; - height: 100vh; - - .page-header, - .page-footer { - flex: 0; - } - - .page-content { - overflow: hidden; - flex: 1; - } -} diff --git a/frontend/src/components/panels/StreamsPane.js b/frontend/src/components/panels/StreamsPane.js index 9470d7d..4c16cf1 100644 --- a/frontend/src/components/panels/StreamsPane.js +++ b/frontend/src/components/panels/StreamsPane.js @@ -21,12 +21,14 @@ import {Row} from "react-bootstrap"; import ReactJson from "react-json-view"; import backend from "../../backend"; import log from "../../log"; +import rules from "../../model/rules"; import {downloadBlob, getHeaderValue} from "../../utils"; import ButtonField from "../fields/ButtonField"; import ChoiceField from "../fields/ChoiceField"; import MessageAction from "../objects/MessageAction"; import "./StreamsPane.scss"; +const reactStringReplace = require("react-string-replace"); const classNames = require("classnames"); class StreamsPane extends Component { @@ -77,11 +79,9 @@ class StreamsPane extends Component { }; tryParseConnectionMessage = (connectionMessage) => { + const isClient = connectionMessage["from_client"]; if (connectionMessage.metadata == null) { - return connectionMessage.content; - } - if (connectionMessage["is_metadata_continuation"]) { - return <span style={{"fontSize": "12px"}}>**already parsed in previous messages**</span>; + return this.highlightRules(connectionMessage.content, isClient); } let unrollMap = (obj) => obj == null ? null : Object.entries(obj).map(([key, value]) => @@ -96,7 +96,7 @@ class StreamsPane extends Component { return <span className="type-http-request"> <p style={{"marginBottom": "7px"}}><strong>{m.method}</strong> {url} {m.protocol}</p> {unrollMap(m.headers)} - <div style={{"margin": "20px 0"}}>{m.body}</div> + <div style={{"margin": "20px 0"}}>{this.highlightRules(m.body, isClient)}</div> {unrollMap(m.trailers)} </span>; case "http-response": @@ -108,20 +108,44 @@ class StreamsPane extends Component { body = <ReactJson src={json} theme="grayscale" collapsed={false} displayDataTypes={false}/>; } catch (e) { log.error(e); + body = m.body; } } return <span className="type-http-response"> <p style={{"marginBottom": "7px"}}>{m.protocol} <strong>{m.status}</strong></p> {unrollMap(m.headers)} - <div style={{"margin": "20px 0"}}>{body}</div> + <div style={{"margin": "20px 0"}}>{this.highlightRules(body, isClient)}</div> {unrollMap(m.trailers)} </span>; default: - return connectionMessage.content; + return this.highlightRules(connectionMessage.content, isClient); } }; + highlightRules = (content, isClient) => { + let streamContent = content; + this.props.connection["matched_rules"].forEach(ruleId => { + const rule = rules.ruleById(ruleId); + rule.patterns.forEach(pattern => { + if ((!isClient && pattern.direction === 1) || (isClient && pattern.direction === 2)) { + return; + } + let flags = ""; + pattern["caseless"] && (flags += "i"); + pattern["dot_all"] && (flags += "s"); + pattern["multi_line"] && (flags += "m"); + pattern["unicode_property"] && (flags += "u"); + const regex = new RegExp("(" + pattern.regex + ")", flags); + streamContent = reactStringReplace(streamContent, regex, (match, i) => ( + <span key={i} className="matched-occurrence" style={{"backgroundColor": rule.color}}>{match}</span> + )); + }); + }); + + return streamContent; + }; + connectionsActions = (connectionMessage) => { if (!connectionMessage.metadata) { return null; @@ -187,7 +211,7 @@ class StreamsPane extends Component { }; const content = this.state.messages || []; - let payload = content.map((c, i) => + let payload = content.filter((c) => !c["is_metadata_continuation"]).map((c, i) => <div key={`content-${i}`} className={classNames("connection-message", c["from_client"] ? "from-client" : "from-server")}> <div className="connection-message-header container-fluid"> diff --git a/frontend/src/components/panels/StreamsPane.scss b/frontend/src/components/panels/StreamsPane.scss index 1f641f3..3857068 100644 --- a/frontend/src/components/panels/StreamsPane.scss +++ b/frontend/src/components/panels/StreamsPane.scss @@ -18,6 +18,12 @@ &:hover::-webkit-scrollbar-thumb { background: $color-secondary-2; } + + .matched-occurrence { + font-weight: 500; + color: $color-primary-4; + border-radius: 2px; + } } .connection-message { @@ -32,8 +38,11 @@ .connection-message-info { font-size: 11px; + overflow: hidden; margin-top: 6px; margin-left: -10px; + white-space: nowrap; + text-overflow: ellipsis; } .connection-message-actions { @@ -97,8 +106,11 @@ .header-info { font-size: 12px; + overflow: hidden; padding-top: 7px; padding-left: 25px; + white-space: nowrap; + text-overflow: ellipsis; } .header-actions { |