aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js
diff options
context:
space:
mode:
authorJason <jason.daurus@gmail.com>2016-06-22 00:49:21 +0800
committerJason <jason.daurus@gmail.com>2016-06-22 00:49:21 +0800
commit0cab9ef1fae927f9ef365526262bef32bd1b526b (patch)
treee3d64264e0239f21e71b1c2132443001fdadd363 /web/src/js
parent9cb5b0af9db83d84af0bdb45d56a9755b400c212 (diff)
parent4576dbf8aac8996f7f87320aba3132b657b02278 (diff)
downloadmitmproxy-0cab9ef1fae927f9ef365526262bef32bd1b526b.tar.gz
mitmproxy-0cab9ef1fae927f9ef365526262bef32bd1b526b.tar.bz2
mitmproxy-0cab9ef1fae927f9ef365526262bef32bd1b526b.zip
Merge remote-tracking branch 'origin/master' into websocket
Conflicts: mitmproxy/web/static/app.js web/src/js/components/ProxyApp.jsx
Diffstat (limited to 'web/src/js')
-rw-r--r--web/src/js/__tests__/ducks/ui.js35
-rw-r--r--web/src/js/__tests__/utils.js8
-rw-r--r--web/src/js/actions.js23
-rw-r--r--web/src/js/components/Footer.jsx9
-rw-r--r--web/src/js/components/Header.jsx9
-rw-r--r--web/src/js/components/Header/FlowMenu.jsx10
-rw-r--r--web/src/js/components/Header/MainMenu.jsx39
-rw-r--r--web/src/js/components/Header/OptionMenu.jsx33
-rw-r--r--web/src/js/components/ProxyApp.jsx6
-rw-r--r--web/src/js/components/common/Button.jsx6
-rw-r--r--web/src/js/ducks/settings.js20
-rw-r--r--web/src/js/ducks/ui.js4
12 files changed, 116 insertions, 86 deletions
diff --git a/web/src/js/__tests__/ducks/ui.js b/web/src/js/__tests__/ducks/ui.js
new file mode 100644
index 00000000..81ae852c
--- /dev/null
+++ b/web/src/js/__tests__/ducks/ui.js
@@ -0,0 +1,35 @@
+jest.unmock("../../ducks/ui");
+jest.unmock("../../ducks/flows");
+
+import reducer, {setActiveMenu} from '../../ducks/ui';
+import {SELECT_FLOW} from '../../ducks/flows';
+
+describe("ui reducer", () => {
+ it("should return the initial state", () => {
+ expect(reducer(undefined, {})).toEqual({ activeMenu: 'Start'})
+ }),
+ it("should return the state for view", () => {
+ expect(reducer(undefined, setActiveMenu('View'))).toEqual({ activeMenu: 'View'})
+ }),
+ it("should change the state to Start when deselecting a flow and we a currently at the flow tab", () => {
+ expect(reducer({activeMenu: 'Flow'},
+ { type: SELECT_FLOW,
+ currentSelection: '1',
+ flowId : undefined
+ })).toEqual({ activeMenu: 'Start'})
+ }),
+ it("should change the state to Flow when we selected a flow and no flow was selected before", () => {
+ expect(reducer({activeMenu: 'Start'},
+ { type: SELECT_FLOW,
+ currentSelection: undefined,
+ flowId : '1'
+ })).toEqual({ activeMenu: 'Flow'})
+ }),
+ it("should not change the state to Flow when OPTIONS tab is selected and we selected a flow and a flow as selected before", () => {
+ expect(reducer({activeMenu: 'Options'},
+ { type: SELECT_FLOW,
+ currentSelection: '1',
+ flowId : '2'
+ })).toEqual({ activeMenu: 'Options'})
+ })
+});
diff --git a/web/src/js/__tests__/utils.js b/web/src/js/__tests__/utils.js
index eda740a1..b216d7d4 100644
--- a/web/src/js/__tests__/utils.js
+++ b/web/src/js/__tests__/utils.js
@@ -1,9 +1,9 @@
-jest.unmock("../utils.js");
+jest.unmock("../utils");
-import {formatSize} from "../utils.js"
+import {formatSize} from "../utils"
-describe("utils", function () {
- it("formatSize", function(){
+describe("utils", () => {
+ it("formatSize", () => {
expect(formatSize(1024)).toEqual("1kb");
expect(formatSize(0)).toEqual("0");
expect(formatSize(10)).toEqual("10b");
diff --git a/web/src/js/actions.js b/web/src/js/actions.js
index 588245ae..bb1d0dd6 100644
--- a/web/src/js/actions.js
+++ b/web/src/js/actions.js
@@ -39,27 +39,6 @@ export var ConnectionActions = {
}
};
-export var SettingsActions = {
- update: function (settings) {
-
- $.ajax({
- type: "PUT",
- url: "/settings",
- contentType: 'application/json',
- data: JSON.stringify(settings)
- });
-
- /*
- //Facebook Flux: We do an optimistic update on the client already.
- AppDispatcher.dispatchViewAction({
- type: ActionTypes.SETTINGS_STORE,
- cmd: StoreCmds.UPDATE,
- data: settings
- });
- */
- }
-};
-
export var FlowActions = {
accept: function (flow) {
$.post("/flows/" + flow.id + "/accept");
@@ -119,4 +98,4 @@ export var Query = {
SEARCH: "s",
HIGHLIGHT: "h",
SHOW_EVENTLOG: "e"
-}; \ No newline at end of file
+};
diff --git a/web/src/js/components/Footer.jsx b/web/src/js/components/Footer.jsx
index 1f6de2d7..82d6d8a1 100644
--- a/web/src/js/components/Footer.jsx
+++ b/web/src/js/components/Footer.jsx
@@ -1,11 +1,12 @@
import React from 'react'
+import { connect } from 'react-redux'
import { formatSize } from '../utils.js'
Footer.propTypes = {
settings: React.PropTypes.object.isRequired,
}
-export default function Footer({ settings }) {
+function Footer({ settings }) {
return (
<footer>
{settings.mode && settings.mode != "regular" && (
@@ -44,3 +45,9 @@ export default function Footer({ settings }) {
</footer>
)
}
+
+export default connect(
+ state => ({
+ settings: state.settings.settings,
+ })
+)(Footer)
diff --git a/web/src/js/components/Header.jsx b/web/src/js/components/Header.jsx
index 93ca5154..ab25eb41 100644
--- a/web/src/js/components/Header.jsx
+++ b/web/src/js/components/Header.jsx
@@ -12,10 +12,6 @@ import {setActiveMenu} from '../ducks/ui.js'
class Header extends Component {
static entries = [MainMenu, ViewMenu, OptionMenu]
- static propTypes = {
- settings: PropTypes.object.isRequired,
- }
-
handleClick(active, e) {
e.preventDefault()
this.props.setActiveMenu(active.title)
@@ -24,7 +20,7 @@ class Header extends Component {
}
render() {
- const { settings, updateLocation, query, selectedFlow, activeMenu} = this.props
+ const { updateLocation, query, selectedFlow, activeMenu} = this.props
let entries = [...Header.entries]
if(selectedFlow)
@@ -47,10 +43,9 @@ class Header extends Component {
</nav>
<div className="menu">
<Active
- settings={settings}
updateLocation={updateLocation}
query={query}
- />
+ />
</div>
</header>
)
diff --git a/web/src/js/components/Header/FlowMenu.jsx b/web/src/js/components/Header/FlowMenu.jsx
index 96f42652..abecf0dc 100644
--- a/web/src/js/components/Header/FlowMenu.jsx
+++ b/web/src/js/components/Header/FlowMenu.jsx
@@ -15,10 +15,12 @@ function FlowMenu({ flow }) {
return (
<div>
<div className="menu-row">
- <Button disabled title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={FlowActions.replay.bind(null, flow)} />
- <Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={FlowActions.duplicate.bind(null, flow)} />
- <Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={FlowActions.delete.bind(null, flow)}/>
- <Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/>
+ <Button disabled={!flow.intercepted} title="[a]ccept intercepted flow" text="Accept" icon="fa-play" onClick={() => FlowActions.accept(flow)} />
+ <Button title="[r]eplay flow" text="Replay" icon="fa-repeat" onClick={FlowActions.replay.bind(null, flow)} />
+ <Button title="[D]uplicate flow" text="Duplicate" icon="fa-copy" onClick={FlowActions.duplicate.bind(null, flow)} />
+ <Button title="[d]elete flow" text="Delete" icon="fa-trash" onClick={FlowActions.delete.bind(null, flow)}/>
+ <Button disabled={!flow.modified} title="revert changes to flow [V]" text="Revert" icon="fa-history" onClick={() => FlowActions.revert(flow)} />
+ <Button title="download" text="Download" icon="fa-download" onClick={() => window.location = MessageUtils.getContentURL(flow, flow.response)}/>
</div>
<div className="clearfix"/>
</div>
diff --git a/web/src/js/components/Header/MainMenu.jsx b/web/src/js/components/Header/MainMenu.jsx
index 7b0b542c..a466a980 100644
--- a/web/src/js/components/Header/MainMenu.jsx
+++ b/web/src/js/components/Header/MainMenu.jsx
@@ -1,8 +1,8 @@
import React, { Component, PropTypes } from 'react'
+import { connect } from 'react-redux'
import FilterInput from './FilterInput'
import { Query } from '../../actions.js'
-import {setInterceptPattern} from "../../ducks/settings"
-import { connect } from 'react-redux'
+import { updateSettings } from '../../ducks/settings'
class MainMenu extends Component {
@@ -10,14 +10,16 @@ class MainMenu extends Component {
static route = 'flows'
static propTypes = {
- settings: React.PropTypes.object.isRequired,
+ query: PropTypes.object.isRequired,
+ settings: PropTypes.object.isRequired,
+ updateLocation: PropTypes.func.isRequired,
+ onSettingsChange: PropTypes.func.isRequired,
}
constructor(props, context) {
super(props, context)
this.onSearchChange = this.onSearchChange.bind(this)
this.onHighlightChange = this.onHighlightChange.bind(this)
- this.onInterceptChange = this.onInterceptChange.bind(this)
}
onSearchChange(val) {
@@ -28,16 +30,8 @@ class MainMenu extends Component {
this.props.updateLocation(undefined, { [Query.HIGHLIGHT]: val })
}
- onInterceptChange(val) {
- this.props.setInterceptPattern(val);
- }
-
render() {
- const { query, settings } = this.props
-
- const search = query[Query.SEARCH] || ''
- const highlight = query[Query.HIGHLIGHT] || ''
- const intercept = settings.intercept || ''
+ const { query, settings, onSettingsChange } = this.props
return (
<div>
@@ -47,7 +41,7 @@ class MainMenu extends Component {
placeholder="Search"
type="search"
color="black"
- value={search}
+ value={query[Query.SEARCH] || ''}
onChange={this.onSearchChange}
/>
<FilterInput
@@ -55,7 +49,7 @@ class MainMenu extends Component {
placeholder="Highlight"
type="tag"
color="hsl(48, 100%, 50%)"
- value={highlight}
+ value={query[Query.HIGHLIGHT] || ''}
onChange={this.onHighlightChange}
/>
<FilterInput
@@ -63,8 +57,8 @@ class MainMenu extends Component {
placeholder="Intercept"
type="pause"
color="hsl(208, 56%, 53%)"
- value={intercept}
- onChange={this.onInterceptChange}
+ value={settings.intercept || ''}
+ onChange={intercept => onSettingsChange({ intercept })}
/>
</div>
<div className="clearfix"></div>
@@ -73,6 +67,11 @@ class MainMenu extends Component {
}
}
-export default connect(undefined, {
- setInterceptPattern
-})(MainMenu);
+export default connect(
+ state => ({
+ settings: state.settings.settings,
+ }),
+ {
+ onSettingsChange: updateSettings,
+ }
+)(MainMenu);
diff --git a/web/src/js/components/Header/OptionMenu.jsx b/web/src/js/components/Header/OptionMenu.jsx
index 44f309fd..f871ec92 100644
--- a/web/src/js/components/Header/OptionMenu.jsx
+++ b/web/src/js/components/Header/OptionMenu.jsx
@@ -1,61 +1,72 @@
import React, { PropTypes } from 'react'
+import { connect } from 'react-redux'
import ToggleButton from '../common/ToggleButton'
import ToggleInputButton from '../common/ToggleInputButton'
-import { SettingsActions } from '../../actions.js'
+import { updateSettings } from '../../ducks/settings'
OptionMenu.title = 'Options'
OptionMenu.propTypes = {
settings: PropTypes.object.isRequired,
+ onSettingsChange: PropTypes.func.isRequired,
}
-export default function OptionMenu({ settings }) {
+function OptionMenu({ settings, onSettingsChange }) {
// @todo use settings.map
return (
<div>
<div className="menu-row">
<ToggleButton text="showhost"
checked={settings.showhost}
- onToggle={() => SettingsActions.update({ showhost: !settings.showhost })}
+ onToggle={() => onSettingsChange({ showhost: !settings.showhost })}
/>
<ToggleButton text="no_upstream_cert"
checked={settings.no_upstream_cert}
- onToggle={() => SettingsActions.update({ no_upstream_cert: !settings.no_upstream_cert })}
+ onToggle={() => onSettingsChange({ no_upstream_cert: !settings.no_upstream_cert })}
/>
<ToggleButton text="rawtcp"
checked={settings.rawtcp}
- onToggle={() => SettingsActions.update({ rawtcp: !settings.rawtcp })}
+ onToggle={() => onSettingsChange({ rawtcp: !settings.rawtcp })}
/>
<ToggleButton text="http2"
checked={settings.http2}
- onToggle={() => SettingsActions.update({ http2: !settings.http2 })}
+ onToggle={() => onSettingsChange({ http2: !settings.http2 })}
/>
<ToggleButton text="anticache"
checked={settings.anticache}
- onToggle={() => SettingsActions.update({ anticache: !settings.anticache })}
+ onToggle={() => onSettingsChange({ anticache: !settings.anticache })}
/>
<ToggleButton text="anticomp"
checked={settings.anticomp}
- onToggle={() => SettingsActions.update({ anticomp: !settings.anticomp })}
+ onToggle={() => onSettingsChange({ anticomp: !settings.anticomp })}
/>
<ToggleInputButton name="stickyauth" placeholder="Sticky auth filter"
checked={!!settings.stickyauth}
txt={settings.stickyauth || ''}
- onToggleChanged={txt => SettingsActions.update({ stickyauth: !settings.stickyauth ? txt : null })}
+ onToggleChanged={txt => onSettingsChange({ stickyauth: !settings.stickyauth ? txt : null })}
/>
<ToggleInputButton name="stickycookie" placeholder="Sticky cookie filter"
checked={!!settings.stickycookie}
txt={settings.stickycookie || ''}
- onToggleChanged={txt => SettingsActions.update({ stickycookie: !settings.stickycookie ? txt : null })}
+ onToggleChanged={txt => onSettingsChange({ stickycookie: !settings.stickycookie ? txt : null })}
/>
<ToggleInputButton name="stream" placeholder="stream..."
checked={!!settings.stream}
txt={settings.stream || ''}
inputType="number"
- onToggleChanged={txt => SettingsActions.update({ stream: !settings.stream ? txt : null })}
+ onToggleChanged={txt => onSettingsChange({ stream: !settings.stream ? txt : null })}
/>
</div>
<div className="clearfix"/>
</div>
)
}
+
+export default connect(
+ state => ({
+ settings: state.settings.settings,
+ }),
+ {
+ onSettingsChange: updateSettings,
+ }
+)(OptionMenu)
diff --git a/web/src/js/components/ProxyApp.jsx b/web/src/js/components/ProxyApp.jsx
index 89bd95fd..84564c32 100644
--- a/web/src/js/components/ProxyApp.jsx
+++ b/web/src/js/components/ProxyApp.jsx
@@ -120,11 +120,11 @@ class ProxyAppMain extends Component {
}
render() {
- const { showEventLog, location, children, settings } = this.props
+ const { showEventLog, location, children } = this.props
const query = this.getQuery()
return (
<div id="container" tabIndex="0" onKeyDown={this.onKeyDown}>
- <Header ref="header" settings={settings} updateLocation={this.updateLocation} query={query} />
+ <Header ref="header" updateLocation={this.updateLocation} query={query} />
{React.cloneElement(
children,
{ ref: 'view', location, query, updateLocation: this.updateLocation }
@@ -132,7 +132,7 @@ class ProxyAppMain extends Component {
{showEventLog && (
<EventLog key="eventlog"/>
)}
- <Footer settings={settings}/>
+ <Footer />
</div>
)
}
diff --git a/web/src/js/components/common/Button.jsx b/web/src/js/components/common/Button.jsx
index cc2fe9dd..574288df 100644
--- a/web/src/js/components/common/Button.jsx
+++ b/web/src/js/components/common/Button.jsx
@@ -5,9 +5,11 @@ Button.propTypes = {
text: PropTypes.string.isRequired
}
-export default function Button({ onClick, text, icon }) {
+export default function Button({ onClick, text, icon, disabled }) {
return (
- <div className={"btn btn-default"} onClick={onClick}>
+ <div className={"btn btn-default"}
+ onClick={onClick}
+ disabled={disabled}>
<i className={"fa fa-fw " + icon}/>
&nbsp;
{text}
diff --git a/web/src/js/ducks/settings.js b/web/src/js/ducks/settings.js
index 73c62120..3e6c8366 100644
--- a/web/src/js/ducks/settings.js
+++ b/web/src/js/ducks/settings.js
@@ -1,8 +1,8 @@
-import {fetchApi} from "../utils";
+import {fetchApi} from '../utils';
-export const REQUEST_SETTINGS = "REQUEST_SETTINGS"
-export const RECEIVE_SETTINGS = "RECEIVE_SETTINGS"
-export const UPDATE_SETTINGS = "UPDATE_SETTINGS"
+export const REQUEST_SETTINGS = 'REQUEST_SETTINGS'
+export const RECEIVE_SETTINGS = 'RECEIVE_SETTINGS'
+export const UPDATE_SETTINGS = 'UPDATE_SETTINGS'
const defaultState = {
settings: {},
@@ -49,20 +49,20 @@ export default function reducer(state = defaultState, action) {
export function updateSettings(event) {
/* This action creator takes all WebSocket events */
- if (event.cmd === "update") {
+ if (event.cmd === 'update') {
return {
type: UPDATE_SETTINGS,
settings: event.data
}
}
- console.error("unknown settings update", event)
+ console.error('unknown settings update', event)
}
export function fetchSettings() {
return dispatch => {
dispatch({type: REQUEST_SETTINGS})
- return fetchApi("/settings")
+ return fetchApi('/settings')
.then(response => response.json())
.then(json =>
dispatch({type: RECEIVE_SETTINGS, settings: json.data})
@@ -71,7 +71,7 @@ export function fetchSettings() {
}
}
-export function setInterceptPattern(intercept) {
- return dispatch =>
- fetchApi.put("/settings", {intercept})
+export function updateSettings(settings) {
+ fetchApi.put('/settings', settings)
+ return { type: SET_INTERCEPT }
}
diff --git a/web/src/js/ducks/ui.js b/web/src/js/ducks/ui.js
index 28a13ea4..c17e042b 100644
--- a/web/src/js/ducks/ui.js
+++ b/web/src/js/ducks/ui.js
@@ -1,5 +1,5 @@
-import { SELECT_FLOW } from './flows'
-const SET_ACTIVE_MENU = 'SET_ACTIVE_MENU'
+import {SELECT_FLOW} from "./flows"
+export const SET_ACTIVE_MENU = 'SET_ACTIVE_MENU';
const defaultState = {