Bring in the necessary changes from f74a52d4dc

This commit is contained in:
M. Mert Yildiran 2021-08-25 00:07:05 +03:00
parent ffc7e05b44
commit 4709bae0ee
No known key found for this signature in database
GPG Key ID: D42ADB236521BF7A
49 changed files with 187 additions and 271 deletions

View File

@ -159,3 +159,15 @@ Such validation may test response for specific JSON fields, headers, etc.
Please see [API RULES](docs/POLICY_RULES.md) page for more details and syntax.
## How to Run local UI
- run from mizu/agent `go run main.go --hars-read --hars-dir <folder>`
- copy Har files into the folder from last command
- change `MizuWebsocketURL` and `apiURL` in `api.js` file
- run from mizu/ui - `npm run start`
- open browser on `localhost:3000`

View File

@ -32,6 +32,8 @@ var apiServerMode = flag.Bool("api-server", false, "Run in API server mode with
var standaloneMode = flag.Bool("standalone", false, "Run in standalone tapper and API mode")
var apiServerAddress = flag.String("api-server-address", "", "Address of mizu API server")
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
var extensions []*tapApi.Extension // global
var extensionsMap map[string]*tapApi.Extension // global
@ -43,8 +45,8 @@ func main() {
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
tapOpts := &tap.TapOpts{HostMode: hostMode}
if !*tapperMode && !*apiServerMode && !*standaloneMode {
panic("One of the flags --tap, --api or --standalone must be provided")
if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode {
panic("One of the flags --tap, --api or --standalone or --hars-read must be provided")
}
if *standaloneMode {
@ -90,6 +92,13 @@ func main() {
go api.StartReadingEntries(socketHarOutChannel, nil, extensionsMap)
hostApi(socketHarOutChannel)
} else if *harsReaderMode {
socketHarOutChannel := make(chan *tapApi.OutputChannelItem, 1000)
// filteredHarChannel := make(chan *tap.OutputChannelItem)
// go filterHarItems(socketHarOutChannel, filteredHarChannel, getTrafficFilteringOptions())
go api.StartReadingEntries(socketHarOutChannel, harsDir, extensionsMap)
hostApi(nil)
}
signalChan := make(chan os.Signal, 1)

View File

@ -1,4 +1,4 @@
@import 'components/style/variables.module'
@import './variables.module'
.mizuApp
background-color: $main-background-color
@ -22,4 +22,4 @@
margin-left: 10px
font-size: 11px
font-weight: bold
color: $light-blue-color
color: $light-blue-color

View File

@ -2,8 +2,8 @@ import React, {useEffect, useState} from 'react';
import './App.sass';
import logo from './components/assets/Mizu-logo.svg';
import {Button, Snackbar} from "@material-ui/core";
import {HarPage} from "./components/HarPage";
import Tooltip from "./components/Tooltip";
import {TrafficPage} from "./components/TrafficPage";
import Tooltip from "./components/UI/Tooltip";
import {makeStyles} from "@material-ui/core/styles";
import MuiAlert from '@material-ui/lab/Alert';
import Api from "./helpers/api";
@ -116,7 +116,7 @@ const App = () => {
</Tooltip>
}
</div>
<HarPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
<TrafficPage setAnalyzeStatus={setAnalyzeStatus} onTLSDetected={onTLSDetected}/>
<Snackbar open={showTLSWarning && !userDismissedTLSWarning}>
<MuiAlert elevation={6} variant="filled" onClose={() => setUserDismissedTLSWarning(true)} severity="warning">
Mizu is detecting TLS traffic{addressesWithTLS.size ? ` (directed to ${Array.from(addressesWithTLS).join(", ")})` : ''}, this type of traffic will not be displayed.

View File

@ -1,13 +1,13 @@
import {HarEntry} from "./HarEntry";
import React, {useCallback, useEffect, useMemo, useState} from "react";
import styles from './style/HarEntriesList.module.sass';
import {EntryItem} from "./EntryListItem/EntryListItem";
import React, {useCallback, useEffect, useMemo, useRef, useState} from "react";
import styles from './style/EntriesList.module.sass';
import spinner from './assets/spinner.svg';
import ScrollableFeed from "react-scrollable-feed";
import {StatusType} from "./HarFilters";
import {StatusType} from "./Filters";
import Api from "../helpers/api";
import uninon from "./assets/union.svg";
import down from "./assets/downImg.svg";
interface HarEntriesListProps {
interface EntriesListProps {
entries: any[];
setEntries: (entries: any[]) => void;
focusedEntryId: string;
@ -32,11 +32,13 @@ enum FetchOperator {
const api = new Api();
export const HarEntriesList: React.FC<HarEntriesListProps> = ({entries, setEntries, focusedEntryId, setFocusedEntryId, connectionOpen, noMoreDataTop, setNoMoreDataTop, noMoreDataBottom, setNoMoreDataBottom, methodsFilter, statusFilter, pathFilter, listEntryREF, onScrollEvent, scrollableList}) => {
export const EntriesList: React.FC<EntriesListProps> = ({entries, setEntries, focusedEntryId, setFocusedEntryId, connectionOpen, noMoreDataTop, setNoMoreDataTop, noMoreDataBottom, setNoMoreDataBottom, methodsFilter, statusFilter, pathFilter, listEntryREF, onScrollEvent, scrollableList}) => {
const [loadMoreTop, setLoadMoreTop] = useState(false);
const [isLoadingTop, setIsLoadingTop] = useState(false);
const scrollableRef = useRef(null);
useEffect(() => {
const list = document.getElementById('list').firstElementChild;
list.addEventListener('scroll', (e) => {
@ -114,24 +116,20 @@ export const HarEntriesList: React.FC<HarEntriesListProps> = ({entries, setEntri
{isLoadingTop && <div className={styles.spinnerContainer}>
<img alt="spinner" src={spinner} style={{height: 25}}/>
</div>}
<ScrollableFeed onScroll={(isAtBottom) => onScrollEvent(isAtBottom)}>
<ScrollableFeed ref={scrollableRef} onScroll={(isAtBottom) => onScrollEvent(isAtBottom)}>
{noMoreDataTop && !connectionOpen && <div id="noMoreDataTop" className={styles.noMoreDataAvailable}>No more data available</div>}
{filteredEntries.map(entry => <HarEntry key={entry.id}
entry={entry}
setFocusedEntryId={setFocusedEntryId}
isSelected={focusedEntryId === entry.id}/>)}
{filteredEntries.map(entry => <EntryItem key={entry.id}
entry={entry}
setFocusedEntryId={setFocusedEntryId}
isSelected={focusedEntryId === entry.id}/>)}
{!connectionOpen && !noMoreDataBottom && <div className={styles.fetchButtonContainer}>
<div className={styles.styledButton} onClick={() => getNewEntries()}>Fetch more entries</div>
</div>}
</ScrollableFeed>
<button type="button"
className={`${styles.btnLive} ${scrollableList ? styles.showButton : styles.hideButton}`}
onClick={(_) => {
const list = listEntryREF.current.firstChild;
if(list instanceof HTMLElement) {
list.scrollTo({ top: list.scrollHeight, behavior: 'smooth' })
}
}}><img alt="Union" src={uninon} />
onClick={(_) => scrollableRef.current.scrollToBottom()}>
<img alt="down" src={down} />
</button>
</div>

View File

@ -1,10 +1,9 @@
import React from "react";
import {singleEntryToHAR} from "./utils";
import HAREntryViewer from "./HarEntryViewer/HAREntryViewer";
import EntryViewer from "./EntryDetailed/EntryViewer";
import {makeStyles} from "@material-ui/core";
import Protocol from "./Protocol"
import StatusCode from "./StatusCode";
import {EndpointPath} from "./EndpointPath";
import Protocol from "./UI/Protocol"
import StatusCode from "./UI/StatusCode";
import {EndpointPath} from "./UI/EndpointPath";
const useStyles = makeStyles(() => ({
entryTitle: {
@ -27,34 +26,32 @@ const useStyles = makeStyles(() => ({
}
}));
interface HarEntryDetailedProps {
harEntry: any;
classes?: any;
interface EntryDetailedProps {
entryData: any
}
export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`;
const HarEntryTitle: React.FC<any> = ({protocol, har}) => {
const EntryTitle: React.FC<any> = ({protocol, data}) => {
const classes = useStyles();
const {log: {entries}} = har;
const {response} = JSON.parse(entries[0].entry);
console.log("data:", data)
const {response} = JSON.parse(data.entry);
return <div className={classes.entryTitle}>
<Protocol protocol={protocol} horizontal={true}/>
<div style={{right: "30px", position: "absolute", display: "flex"}}>
{response.payload && <div style={{margin: "0 18px", opacity: 0.5}}>{formatSize(response.payload.bodySize)}</div>}
<div style={{opacity: 0.5}}>{'rulesMatched' in entries[0] ? entries[0].rulesMatched?.length : '0'} Rules Applied</div>
<div style={{opacity: 0.5}}>{'rulesMatched' in data ? data.rulesMatched?.length : '0'} Rules Applied</div>
</div>
</div>;
};
const HarEntrySummary: React.FC<any> = ({har}) => {
const EntrySummary: React.FC<any> = ({data}) => {
const classes = useStyles();
const {log: {entries}} = har;
const {response, request} = JSON.parse(entries[0].entry);
const {response, request} = JSON.parse(data.entry);
return <div className={classes.entrySummary}>
{response?.payload && response.payload?.details && "status" in response.payload.details && <div style={{marginRight: 8}}>
@ -66,14 +63,12 @@ const HarEntrySummary: React.FC<any> = ({har}) => {
</div>;
};
export const HAREntryDetailed: React.FC<HarEntryDetailedProps> = ({classes, harEntry}) => {
const har = singleEntryToHAR(harEntry.data);
export const EntryDetailed: React.FC<EntryDetailedProps> = ({entryData}) => {
return <>
<HarEntryTitle protocol={harEntry.protocol} har={har}/>
{har && <HarEntrySummary har={har}/>}
<EntryTitle protocol={entryData.protocol} data={entryData.data}/>
{entryData.data && <EntrySummary data={entryData.data}/>}
<>
{har && <HAREntryViewer representation={harEntry.representation} color={harEntry.protocol.background_color}/>}
{entryData.data && <EntryViewer representation={entryData.representation} color={entryData.protocol.background_color}/>}
</>
</>
};

View File

@ -1,4 +1,4 @@
@import '../style/variables.module'
@import '../../variables.module'
.title
display: flex

View File

@ -1,17 +1,17 @@
import styles from "./HAREntrySections.module.sass";
import styles from "./EntrySections.module.sass";
import React, {useState} from "react";
import {SyntaxHighlighter} from "../SyntaxHighlighter/index";
import CollapsibleContainer from "../CollapsibleContainer";
import FancyTextDisplay from "../FancyTextDisplay";
import Checkbox from "../Checkbox";
import {SyntaxHighlighter} from "../UI/SyntaxHighlighter/index";
import CollapsibleContainer from "../UI/CollapsibleContainer";
import FancyTextDisplay from "../UI/FancyTextDisplay";
import Checkbox from "../UI/Checkbox";
import ProtobufDecoder from "protobuf-decoder";
interface HAREntryViewLineProps {
interface EntryViewLineProps {
label: string;
value: number | string;
}
const HAREntryViewLine: React.FC<HAREntryViewLineProps> = ({label, value}) => {
const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value}) => {
return (label && value && <tr className={styles.dataLine}>
<td className={styles.dataKey}>{label}</td>
<td>
@ -27,13 +27,13 @@ const HAREntryViewLine: React.FC<HAREntryViewLineProps> = ({label, value}) => {
}
interface HAREntrySectionCollapsibleTitleProps {
interface EntrySectionCollapsibleTitleProps {
title: string,
color: string,
isExpanded: boolean,
}
const HAREntrySectionCollapsibleTitle: React.FC<HAREntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
return <div className={styles.title}>
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`} style={{backgroundColor: color}}>
{isExpanded ? '-' : '+'}
@ -42,31 +42,31 @@ const HAREntrySectionCollapsibleTitle: React.FC<HAREntrySectionCollapsibleTitleP
</div>
}
interface HAREntrySectionContainerProps {
interface EntrySectionContainerProps {
title: string,
color: string,
}
export const HAREntrySectionContainer: React.FC<HAREntrySectionContainerProps> = ({title, color, children}) => {
export const EntrySectionContainer: React.FC<EntrySectionContainerProps> = ({title, color, children}) => {
const [expanded, setExpanded] = useState(true);
return <CollapsibleContainer
className={styles.collapsibleContainer}
isExpanded={expanded}
onClick={() => setExpanded(!expanded)}
title={<HAREntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
title={<EntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
>
{children}
</CollapsibleContainer>
}
interface HAREntryBodySectionProps {
interface EntryBodySectionProps {
content: any,
color: string,
encoding?: string,
contentType?: string,
}
export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
color,
content,
encoding,
@ -104,11 +104,11 @@ export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
}
return <React.Fragment>
{content && content?.length > 0 && <HAREntrySectionContainer title='Body' color={color}>
{content && content?.length > 0 && <EntrySectionContainer title='Body' color={color}>
<table>
<tbody>
<HAREntryViewLine label={'Mime type'} value={contentType}/>
<HAREntryViewLine label={'Encoding'} value={encoding}/>
<EntryViewLine label={'Mime type'} value={contentType}/>
<EntryViewLine label={'Encoding'} value={encoding}/>
</tbody>
</table>
@ -124,35 +124,35 @@ export const HAREntryBodySection: React.FC<HAREntryBodySectionProps> = ({
code={formatTextBody(content)}
language={content?.mimeType ? getLanguage(content.mimeType) : 'default'}
/>
</HAREntrySectionContainer>}
</EntrySectionContainer>}
</React.Fragment>
}
interface HAREntrySectionProps {
interface EntrySectionProps {
title: string,
color: string,
arrayToIterate: any[],
}
export const HAREntryTableSection: React.FC<HAREntrySectionProps> = ({title, color, arrayToIterate}) => {
export const EntryTableSection: React.FC<EntrySectionProps> = ({title, color, arrayToIterate}) => {
return <React.Fragment>
{
arrayToIterate && arrayToIterate.length > 0 ?
<HAREntrySectionContainer title={title} color={color}>
<EntrySectionContainer title={title} color={color}>
<table>
<tbody>
{arrayToIterate.map(({name, value}, index) => <HAREntryViewLine key={index} label={name}
{arrayToIterate.map(({name, value}, index) => <EntryViewLine key={index} label={name}
value={value}/>)}
</tbody>
</table>
</HAREntrySectionContainer> : <span/>
</EntrySectionContainer> : <span/>
}
</React.Fragment>
}
interface HAREntryPolicySectionProps {
interface EntryPolicySectionProps {
service: string,
title: string,
color: string,
@ -162,13 +162,13 @@ interface HAREntryPolicySectionProps {
}
interface HAREntryPolicySectionCollapsibleTitleProps {
interface EntryPolicySectionCollapsibleTitleProps {
label: string;
matched: string;
isExpanded: boolean;
}
const HAREntryPolicySectionCollapsibleTitle: React.FC<HAREntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
return <div className={styles.title}>
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`}>
{isExpanded ? '-' : '+'}
@ -182,36 +182,36 @@ const HAREntryPolicySectionCollapsibleTitle: React.FC<HAREntryPolicySectionColla
</div>
}
interface HAREntryPolicySectionContainerProps {
interface EntryPolicySectionContainerProps {
label: string;
matched: string;
children?: any;
}
export const HAREntryPolicySectionContainer: React.FC<HAREntryPolicySectionContainerProps> = ({label, matched, children}) => {
export const EntryPolicySectionContainer: React.FC<EntryPolicySectionContainerProps> = ({label, matched, children}) => {
const [expanded, setExpanded] = useState(false);
return <CollapsibleContainer
className={styles.collapsibleContainer}
isExpanded={expanded}
onClick={() => setExpanded(!expanded)}
title={<HAREntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
>
{children}
</CollapsibleContainer>
}
export const HAREntryTablePolicySection: React.FC<HAREntryPolicySectionProps> = ({service, title, color, response, latency, arrayToIterate}) => {
export const EntryTablePolicySection: React.FC<EntryPolicySectionProps> = ({service, title, color, response, latency, arrayToIterate}) => {
// const base64ToJson = response.content.mimeType === "application/json; charset=utf-8" ? JSON.parse(Buffer.from(response.content.text, "base64").toString()) : {};
return <React.Fragment>
{
arrayToIterate && arrayToIterate.length > 0 ?
<>
<HAREntrySectionContainer title={title} color={color}>
<EntrySectionContainer title={title} color={color}>
<table>
<tbody>
{arrayToIterate.map(({rule, matched}, index) => {
return (
<HAREntryPolicySectionContainer key={index} label={rule.Name} matched={matched && (rule.Type === 'latency' ? rule.Latency >= latency : true)? "Success" : "Failure"}>
<EntryPolicySectionContainer key={index} label={rule.Name} matched={matched && (rule.Type === 'latency' ? rule.Latency >= latency : true)? "Success" : "Failure"}>
{
<>
{
@ -251,14 +251,14 @@ export const HAREntryTablePolicySection: React.FC<HAREntryPolicySectionProps> =
}
</>
}
</HAREntryPolicySectionContainer>
</EntryPolicySectionContainer>
)
}
)
}
</tbody>
</table>
</HAREntrySectionContainer>
</EntrySectionContainer>
</> : <span/>
}
</React.Fragment>

View File

@ -1,6 +1,6 @@
@import "../style/variables.module"
@import "../../variables.module"
.harEntry
.Entry
font-family: "Source Sans Pro", Lucida Grande, Tahoma, sans-serif
height: 100%
width: 100%
@ -57,4 +57,4 @@
text-decoration: none
margin-bottom: .5rem
overflow-wrap: anywhere
padding: 5px 0
padding: 5px 0

View File

@ -1,7 +1,7 @@
import React, {useState} from 'react';
import styles from './HAREntryViewer.module.sass';
import Tabs from "../Tabs";
import {HAREntryTableSection, HAREntryBodySection, HAREntryTablePolicySection} from "./HAREntrySections";
import styles from './EntryViewer.module.sass';
import Tabs from "../UI/Tabs";
import {EntryTableSection, EntryBodySection, EntryTablePolicySection} from "./EntrySections";
const SectionsRepresentation: React.FC<any> = ({data, color}) => {
const sections = []
@ -11,12 +11,12 @@ const SectionsRepresentation: React.FC<any> = ({data, color}) => {
switch (row.type) {
case "table":
sections.push(
<HAREntryTableSection key={i} title={row.title} color={color} arrayToIterate={JSON.parse(row.data)}/>
<EntryTableSection key={i} title={row.title} color={color} arrayToIterate={JSON.parse(row.data)}/>
)
break;
case "body":
sections.push(
<HAREntryBodySection key={i} color={color} content={row.data} encoding={row.encoding} contentType={row.mime_type}/>
<EntryBodySection key={i} color={color} content={row.data} encoding={row.encoding} contentType={row.mime_type}/>
)
break;
default:
@ -49,7 +49,7 @@ const AutoRepresentation: React.FC<any> = ({representation, color, isResponseMoc
const {request, response} = JSON.parse(representation);
return <div className={styles.harEntry}>
return <div className={styles.Entry}>
{<div className={styles.body}>
<div className={styles.bodyHeader}>
<Tabs tabs={TABS} currentTab={currentTab} color={color} onChange={setCurrentTab} leftAligned/>
@ -63,7 +63,7 @@ const AutoRepresentation: React.FC<any> = ({representation, color, isResponseMoc
</React.Fragment>}
{currentTab === TABS[2].tab && <React.Fragment>
{// FIXME: Fix here
<HAREntryTablePolicySection service={representation.log.entries[0].service} title={'Rule'} color={color} latency={0} response={response} arrayToIterate={rulesMatched ? rulesMatched : []}/>}
<EntryTablePolicySection service={representation.log.entries[0].service} title={'Rule'} color={color} latency={0} response={response} arrayToIterate={rulesMatched ? rulesMatched : []}/>}
</React.Fragment>}
</div>}
</div>;
@ -76,8 +76,8 @@ interface Props {
showTitle?: boolean;
}
const HAREntryViewer: React.FC<Props> = ({representation, color, isResponseMocked, showTitle=true}) => {
const EntryViewer: React.FC<Props> = ({representation, color, isResponseMocked, showTitle=true}) => {
return <AutoRepresentation representation={representation} color={color} isResponseMocked={isResponseMocked} showTitle={showTitle}/>
};
export default HAREntryViewer;
export default EntryViewer;

View File

@ -1,4 +1,4 @@
@import 'variables.module'
@import '../../variables.module'
.row
display: flex

View File

@ -1,16 +1,16 @@
import React from "react";
import styles from './style/HarEntry.module.sass';
import StatusCode, {getClassification, StatusCodeClassification} from "./StatusCode";
import Protocol, {ProtocolInterface} from "./Protocol"
import {EndpointPath} from "./EndpointPath";
import ingoingIconSuccess from "./assets/ingoing-traffic-success.svg"
import ingoingIconFailure from "./assets/ingoing-traffic-failure.svg"
import ingoingIconNeutral from "./assets/ingoing-traffic-neutral.svg"
import outgoingIconSuccess from "./assets/outgoing-traffic-success.svg"
import outgoingIconFailure from "./assets/outgoing-traffic-failure.svg"
import outgoingIconNeutral from "./assets/outgoing-traffic-neutral.svg"
import styles from './EntryListItem.module.sass';
import StatusCode, {getClassification, StatusCodeClassification} from "../UI/StatusCode";
import Protocol, {ProtocolInterface} from "../UI/Protocol"
import {EndpointPath} from "../UI/EndpointPath";
import ingoingIconSuccess from "../assets/ingoing-traffic-success.svg"
import ingoingIconFailure from "../assets/ingoing-traffic-failure.svg"
import ingoingIconNeutral from "../assets/ingoing-traffic-neutral.svg"
import outgoingIconSuccess from "../assets/outgoing-traffic-success.svg"
import outgoingIconFailure from "../assets/outgoing-traffic-failure.svg"
import outgoingIconNeutral from "../assets/outgoing-traffic-neutral.svg"
interface HAREntry {
interface Entry {
protocol: ProtocolInterface,
method?: string,
summary: string,
@ -34,13 +34,13 @@ interface Rules {
numberOfRules: number;
}
interface HAREntryProps {
entry: HAREntry;
interface EntryProps {
entry: Entry;
setFocusedEntryId: (id: string) => void;
isSelected?: boolean;
}
export const HarEntry: React.FC<HAREntryProps> = ({entry, setFocusedEntryId, isSelected}) => {
export const EntryItem: React.FC<EntryProps> = ({entry, setFocusedEntryId, isSelected}) => {
const classification = getClassification(entry.status_code)
let ingoingIcon;
let outgoingIcon;

View File

@ -1,10 +1,10 @@
import React from "react";
import styles from './style/HarFilters.module.sass';
import {HARFilterSelect} from "./HARFilterSelect";
import styles from './style/Filters.module.sass';
import {FilterSelect} from "./UI/FilterSelect";
import {TextField} from "@material-ui/core";
import {ALL_KEY} from "./Select";
import {ALL_KEY} from "./UI/Select";
interface HarFiltersProps {
interface FiltersProps {
methodsFilter: Array<string>;
setMethodsFilter: (methods: Array<string>) => void;
statusFilter: Array<string>;
@ -13,7 +13,7 @@ interface HarFiltersProps {
setPathFilter: (val: string) => void;
}
export const HarFilters: React.FC<HarFiltersProps> = ({methodsFilter, setMethodsFilter, statusFilter, setStatusFilter, pathFilter, setPathFilter}) => {
export const Filters: React.FC<FiltersProps> = ({methodsFilter, setMethodsFilter, statusFilter, setStatusFilter, pathFilter, setPathFilter}) => {
return <div className={styles.container}>
<MethodFilter methodsFilter={methodsFilter} setMethodsFilter={setMethodsFilter}/>
@ -59,7 +59,7 @@ const MethodFilter: React.FC<MethodFilterProps> = ({methodsFilter, setMethodsFil
}
return <FilterContainer>
<HARFilterSelect
<FilterSelect
items={Object.values(HTTPMethod)}
allowMultiple={true}
value={methodsFilter}
@ -91,7 +91,7 @@ const StatusTypesFilter: React.FC<StatusTypesFilterProps> = ({statusFilter, setS
}
return <FilterContainer>
<HARFilterSelect
<FilterSelect
items={Object.values(StatusType)}
allowMultiple={true}
value={statusFilter}

View File

@ -1,27 +0,0 @@
import prevIcon from "./assets/icon-prev.svg";
import nextIcon from "./assets/icon-next.svg";
import {Box} from "@material-ui/core";
import React from "react";
import styles from './style/HarPaging.module.sass'
import numeral from 'numeral';
interface HarPagingProps {
showPageNumber?: boolean;
}
export const HarPaging: React.FC<HarPagingProps> = ({showPageNumber=false}) => {
return <Box className={styles.HarPaging} display='flex'>
<img src={prevIcon} onClick={() => {
// harStore.data.moveBack(); todo
}} alt="back"/>
{showPageNumber && <span className={styles.text}>
Page <span className={styles.pageNumber}>
{/*{numeral(harStore.data.currentPage).format(0, 0)}*/} //todo
</span>
</span>}
<img src={nextIcon} onClick={() => {
// harStore.data.moveNext(); todo
}} alt="next"/>
</Box>
};

View File

@ -1,14 +1,14 @@
import React, {useEffect, useRef, useState} from "react";
import {HarFilters} from "./HarFilters";
import {HarEntriesList} from "./HarEntriesList";
import {Filters} from "./Filters";
import {EntriesList} from "./EntriesList";
import {makeStyles} from "@material-ui/core";
import "./style/HarPage.sass";
import styles from './style/HarEntriesList.module.sass';
import {HAREntryDetailed} from "./HarEntryDetailed";
import "./style/TrafficPage.sass";
import styles from './style/EntriesList.module.sass';
import {EntryDetailed} from "./EntryDetailed";
import playIcon from './assets/run.svg';
import pauseIcon from './assets/pause.svg';
import variables from './style/variables.module.scss';
import {StatusBar} from "./StatusBar";
import variables from '../variables.module.scss';
import {StatusBar} from "./UI/StatusBar";
import Api, {MizuWebsocketURL} from "../helpers/api";
const useLayoutStyles = makeStyles(() => ({
@ -21,7 +21,7 @@ const useLayoutStyles = makeStyles(() => ({
background: variables.headerBackgoundColor
},
harViewer: {
viewer: {
display: 'flex',
overflowY: 'auto',
height: "calc(100% - 70px)",
@ -36,20 +36,20 @@ enum ConnectionStatus {
Paused
}
interface HarPageProps {
interface TrafficPageProps {
setAnalyzeStatus: (status: any) => void;
onTLSDetected: (destAddress: string) => void;
}
const api = new Api();
export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLSDetected}) => {
const classes = useLayoutStyles();
const [entries, setEntries] = useState([] as any);
const [focusedEntryId, setFocusedEntryId] = useState(null);
const [selectedHarEntry, setSelectedHarEntry] = useState(null);
const [selectedEntryData, setSelectedEntryData] = useState(null);
const [connection, setConnection] = useState(ConnectionStatus.Closed);
const [noMoreDataTop, setNoMoreDataTop] = useState(false);
const [noMoreDataBottom, setNoMoreDataBottom] = useState(false);
@ -129,11 +129,11 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
useEffect(() => {
if (!focusedEntryId) return;
setSelectedHarEntry(null);
setSelectedEntryData(null);
(async () => {
try {
const entryData = await api.getEntry(focusedEntryId);
setSelectedHarEntry(entryData);
setSelectedEntryData(entryData);
} catch (error) {
console.error(error);
}
@ -170,16 +170,16 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
const onScrollEvent = (isAtBottom) => {
isAtBottom ? setDisableScrollList(false) : setDisableScrollList(true)
}
const isScrollable = (element) => {
return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
return element.scrollHeight > element.clientHeight;
};
return (
<div className="HarPage">
<div className="harPageHeader">
<div className="TrafficPage">
<div className="TrafficPageHeader">
<img style={{cursor: "pointer", marginRight: 15, height: 30}} alt="pause"
src={connection === ConnectionStatus.Connected ? pauseIcon : playIcon} onClick={toggleConnection}/>
src={connection === ConnectionStatus.Connected ? pauseIcon : playIcon} onClick={toggleConnection}/>
<div className="connectionText">
{getConnectionTitle()}
<div className={"indicatorContainer " + getConnectionStatusClass(true)}>
@ -187,9 +187,9 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
</div>
</div>
</div>
{entries.length > 0 && <div className="HarPage-Container">
<div className="HarPage-ListContainer">
<HarFilters methodsFilter={methodsFilter}
{entries.length > 0 && <div className="TrafficPage-Container">
<div className="TrafficPage-ListContainer">
<Filters methodsFilter={methodsFilter}
setMethodsFilter={setMethodsFilter}
statusFilter={statusFilter}
setStatusFilter={setStatusFilter}
@ -197,7 +197,7 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
setPathFilter={setPathFilter}
/>
<div className={styles.container}>
<HarEntriesList entries={entries}
<EntriesList entries={entries}
setEntries={setEntries}
focusedEntryId={focusedEntryId}
setFocusedEntryId={setFocusedEntryId}
@ -216,8 +216,7 @@ export const HarPage: React.FC<HarPageProps> = ({setAnalyzeStatus, onTLSDetected
</div>
</div>
<div className={classes.details}>
{selectedHarEntry &&
<HAREntryDetailed harEntry={selectedHarEntry} classes={{root: classes.harViewer}}/>}
{selectedEntryData && <EntryDetailed entryData={selectedEntryData}/>}
</div>
</div>}
{tappingStatus?.pods != null && <StatusBar tappingStatus={tappingStatus}/>}

View File

@ -1,6 +1,6 @@
import React, {useState} from "react";
import collapsedImg from "./assets/collapsed.svg";
import expandedImg from "./assets/expanded.svg";
import collapsedImg from "../assets/collapsed.svg";
import expandedImg from "../assets/expanded.svg";
import "./style/CollapsibleContainer.sass";
interface Props {

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import duplicateImg from "./assets/duplicate.svg";
import duplicateImg from "../assets/duplicate.svg";
import './style/FancyTextDisplay.sass';
interface Props {

View File

@ -1,9 +1,9 @@
import React from "react";
import { MenuItem } from '@material-ui/core';
import style from './style/HARFilterSelect.module.sass';
import style from './style/FilterSelect.module.sass';
import { Select, SelectProps } from "./Select";
interface HARFilterSelectProps extends SelectProps {
interface FilterSelectProps extends SelectProps {
items: string[];
value: string | string[];
onChange: (string) => void;
@ -12,7 +12,7 @@ interface HARFilterSelectProps extends SelectProps {
transformDisplay?: (string) => string;
}
export const HARFilterSelect: React.FC<HARFilterSelectProps> = ({items, value, onChange, label, allowMultiple= false, transformDisplay}) => {
export const FilterSelect: React.FC<FilterSelectProps> = ({items, value, onChange, label, allowMultiple= false, transformDisplay}) => {
return <Select
value={value}
multiple={allowMultiple}
@ -20,7 +20,7 @@ export const HARFilterSelect: React.FC<HARFilterSelectProps> = ({items, value, o
onChange={onChange}
transformDisplay={transformDisplay}
labelOnTop={true}
labelClassName={style.HARSelectLabel}
labelClassName={style.SelectLabel}
trimItemsWhenMultiple={true}
>
{items?.map(item => <MenuItem key={item} value={item}><span className='uppercase'>{item}</span></MenuItem>)}

View File

@ -1,4 +1,4 @@
import {ReactComponent as DefaultIconDown} from './assets/default_icon_down.svg';
import {ReactComponent as DefaultIconDown} from '../assets/default_icon_down.svg';
import {MenuItem, Select as MUISelect} from '@material-ui/core';
import React from 'react';
import {SelectProps as MUISelectProps} from '@material-ui/core/Select/Select';

View File

@ -7,11 +7,11 @@ export enum StatusCodeClassification {
NEUTRAL = "neutral"
}
interface HAREntryProps {
interface EntryProps {
statusCode: number
}
const StatusCode: React.FC<HAREntryProps> = ({statusCode}) => {
const StatusCode: React.FC<EntryProps> = ({statusCode}) => {
const classification = getClassification(statusCode)

View File

@ -1,7 +1,7 @@
import Tooltip from "./Tooltip";
import React from "react";
import {makeStyles} from '@material-ui/core/styles';
import variables from './style/variables.module.scss';
import variables from '../../variables.module.scss';
interface Tab {
tab: string,

View File

@ -0,0 +1,3 @@
.SelectLabel
color: #8f9bb2
font-size: 11px

View File

@ -1,5 +1,3 @@
@import 'variables.module'
.base
display: inline-block
text-align: center

View File

@ -1,4 +1,4 @@
@import 'variables.module.scss'
@import '../../../variables.module'
.statusBar
position: absolute
@ -32,4 +32,4 @@
.expandedStatusBar
max-height: 100vh
padding-bottom: 15px
padding-bottom: 15px

View File

@ -1,4 +1,4 @@
@import 'variables.module'
@import '../../../variables.module'
.base
border-radius: 4px

View File

@ -1,4 +1,4 @@
@import 'variables.module'
@import '../../../variables.module'
.protocol
border-radius: 4px
@ -24,4 +24,4 @@
-khtml-user-select: none
-moz-user-select: none
-ms-user-select: none
user-select: none
user-select: none

View File

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

View File

@ -1,4 +1,4 @@
@import "variables.module"
@import "../../variables.module"
.list
overflow: scroll

View File

@ -1,4 +1,4 @@
@import "variables.module"
@import "../../variables.module"
.container
display: flex

View File

@ -1,3 +0,0 @@
.HARSelectLabel
color: #8f9bb2
font-size: 11px

View File

@ -1,7 +0,0 @@
.loader
margin: 30px auto 0
.har
display: flex
overflow: scroll
height: calc(100% - 1.75rem)

View File

@ -1,16 +0,0 @@
.HarPaging
justify-content: center
align-items: center
padding-bottom: 10px
img
cursor: pointer
.text
color: #8f9bb2
font-size: 14px
padding: 0 10px
.pageNumber
color: #fff
font-weight: 600

View File

@ -1,6 +1,6 @@
@import 'variables.module.scss'
@import '../../variables.module.scss'
.HarPage
.TrafficPage
width: 100%
display: flex
flex-direction: column
@ -8,34 +8,34 @@
flex-grow: 1
height: calc(100vh - 70px)
.harPageHeader
.TrafficPageHeader
padding: 20px 24px
display: flex
align-items: center
background-color: $header-background-color
.HarPage-Header
.TrafficPage-Header
display: flex
height: 2.5%
justify-content: space-between
align-items: center
padding: 18px 15px
.HarPage-Header-Image
.TrafficPage-Header-Image
width: 22px
height: 22px
.HarPage-Header-Text
.TrafficPage-Header-Text
margin-left: 10px
font-family: 'Source Sans Pro', serif
font-size: 14px
font-weight: bold
color: #f7f9fc
.HarPage-Header-Actions
.TrafficPage-Header-Actions
margin-left: auto
.HarPage-Header-Actions-Image
.TrafficPage-Header-Actions-Image
width: 22px
height: 22px
cursor: pointer
@ -43,7 +43,7 @@
margin-left: auto
transform: translate(0 ,25%)
.HarPage-Viewer
.TrafficPage-Viewer
height: 96.5%
overflow: auto
@ -53,25 +53,25 @@
display: block
overflow-y: auto
.harContent
.TrafficContent
box-sizing: border-box
height: calc(100% - 60px)
overflow: scroll
.HarPage-Container
.TrafficPage-Container
display: flex
flex-grow: 1
overflow: hidden
background-color: $data-background-color
.HarPage-ListContainer
.TrafficPage-ListContainer
display: flex
flex-grow: 1
overflow: hidden
padding-left: 24px
flex-direction: column
.HarPage-DetailContainer
.TrafficPage-DetailContainer
width: 45vw
background-color: #171c30
flex: 0 0 50%

View File

@ -1,35 +0,0 @@
export const singleEntryToHAR = (entry) => {
if (!entry) return null;
const modifiedEntry = {
...entry,
"startedDateTime": "2019-10-08T11:49:51.090+03:00",
"cache": {},
"timings": {
"blocked": -1,
"dns": -1,
"connect": -1,
"ssl": -1,
"send": -1,
"wait": -1,
"receive": -1
},
"time": -1
};
const har = {
log: {
entries: [modifiedEntry],
version: "1.2",
creator: {
"name": "Firefox",
"version": "69.0.1"
}
}
}
return har;
};
export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`;

View File

@ -1,10 +0,0 @@
import {useState} from "react";
export default function useToggle(initialState: boolean = false): [boolean, () => void] {
const [isToggled, setToggled] = useState(initialState);
return [isToggled, () => {
setToggled(!isToggled)
}];
}

View File

@ -1,4 +1,4 @@
@import 'src/components/style/variables.module'
@import './variables.module'
html,
body