aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--README.rst17
-rw-r--r--mitmproxy/cmdline.py13
-rw-r--r--mitmproxy/contentviews.py19
-rw-r--r--mitmproxy/controller.py9
-rw-r--r--mitmproxy/models/__init__.py4
-rw-r--r--mitmproxy/platform/osx.py2
-rw-r--r--mitmproxy/tnetstring.py4
-rw-r--r--mitmproxy/web/static/app.js33
-rw-r--r--test/mitmproxy/completion/bbb/Readme.md2
-rw-r--r--test/mitmproxy/console/test_pathedit.py24
-rw-r--r--test/mitmproxy/mastertest.py5
-rw-r--r--test/mitmproxy/test_cmdline.py12
-rw-r--r--test/mitmproxy/test_contentview.py70
-rw-r--r--test/mitmproxy/test_custom_contentview.py2
-rw-r--r--tox.ini2
-rw-r--r--web/package.json1
-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
28 files changed, 260 insertions, 161 deletions
diff --git a/README.rst b/README.rst
index 983f50fb..a6e7f56c 100644
--- a/README.rst
+++ b/README.rst
@@ -19,16 +19,25 @@ that creatively violate the standards.
Documentation & Help
--------------------
-Documentation, tutorials and precompiled binaries can be found on the mitmproxy
+
+General information, tutorials, and precompiled binaries can be found on the mitmproxy
and pathod websites.
|mitmproxy_site| |pathod_site|
+
The latest documentation for mitmproxy is also available on ReadTheDocs.
|mitmproxy_docs|
-You can join our developer chat on Slack.
+
+Join our discussion forum on Discourse to ask questions, help
+each other solve problems, and come up with new ideas for the project.
+
+|mitmproxy_discourse|
+
+
+Join our developer chat on Slack if you would like to hack on mitmproxy itself.
|slack|
@@ -155,6 +164,10 @@ PR checks will fail and block merging. We are using this command to check for st
:target: http://docs.mitmproxy.org/en/latest/
:alt: mitmproxy documentation
+.. |mitmproxy_discourse| image:: https://shields.mitmproxy.org/api/https%3A%2F%2F-discourse.mitmproxy.org-orange.svg
+ :target: https://discourse.mitmproxy.org
+ :alt: Discourse: mitmproxy
+
.. |slack| image:: http://slack.mitmproxy.org/badge.svg
:target: http://slack.mitmproxy.org/
:alt: Slack Developer Chat
diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py
index 77cdb8ca..d46051a2 100644
--- a/mitmproxy/cmdline.py
+++ b/mitmproxy/cmdline.py
@@ -9,6 +9,7 @@ import configargparse
from mitmproxy import filt
from mitmproxy.proxy import config
from netlib import human
+from netlib import strutils
from netlib import tcp
from netlib import version
from netlib.http import url
@@ -73,7 +74,7 @@ def parse_replace_hook(s):
try:
re.compile(regex)
except re.error as e:
- raise ParseException("Malformed replacement regex: %s" % str(e.message))
+ raise ParseException("Malformed replacement regex: %s" % str(e))
return patt, regex, replacement
@@ -109,7 +110,7 @@ def parse_setheader(s):
def parse_server_spec(spec):
try:
p = url.parse(spec)
- if p[0] not in ("http", "https"):
+ if p[0] not in (b"http", b"https"):
raise ValueError()
except ValueError:
raise configargparse.ArgumentTypeError(
@@ -127,7 +128,7 @@ def parse_upstream_auth(auth):
raise configargparse.ArgumentTypeError(
"Invalid upstream auth specification: %s" % auth
)
- return "Basic" + " " + base64.b64encode(auth)
+ return b"Basic" + b" " + base64.b64encode(strutils.always_bytes(auth))
def get_common_options(options):
@@ -147,13 +148,13 @@ def get_common_options(options):
try:
p = parse_replace_hook(i)
except ParseException as e:
- raise configargparse.ArgumentTypeError(e.message)
+ raise configargparse.ArgumentTypeError(e)
reps.append(p)
for i in options.replace_file:
try:
patt, rex, path = parse_replace_hook(i)
except ParseException as e:
- raise configargparse.ArgumentTypeError(e.message)
+ raise configargparse.ArgumentTypeError(e)
try:
v = open(path, "rb").read()
except IOError as e:
@@ -167,7 +168,7 @@ def get_common_options(options):
try:
p = parse_setheader(i)
except ParseException as e:
- raise configargparse.ArgumentTypeError(e.message)
+ raise configargparse.ArgumentTypeError(e)
setheaders.append(p)
if options.outfile and options.outfile[0] == options.rfile:
diff --git a/mitmproxy/contentviews.py b/mitmproxy/contentviews.py
index 90dafca0..7c9e4ba1 100644
--- a/mitmproxy/contentviews.py
+++ b/mitmproxy/contentviews.py
@@ -26,7 +26,7 @@ import lxml.html
import six
from PIL import ExifTags
from PIL import Image
-from six.moves import cStringIO as StringIO
+from six import BytesIO
from mitmproxy import exceptions
from mitmproxy.contrib import jsbeautifier
@@ -64,7 +64,7 @@ KEY_MAX = 30
def pretty_json(s):
# type: (bytes) -> bytes
try:
- p = json.loads(s)
+ p = json.loads(s.decode('utf-8'))
except ValueError:
return None
pretty = json.dumps(p, sort_keys=True, indent=4, ensure_ascii=False)
@@ -143,11 +143,11 @@ class ViewAuto(View):
ct = "%s/%s" % (ct[0], ct[1])
if ct in content_types_map:
return content_types_map[ct][0](data, **metadata)
- elif strutils.isXML(data):
+ elif strutils.isXML(data.decode()):
return get("XML")(data, **metadata)
if metadata.get("query"):
return get("Query")(data, **metadata)
- if data and strutils.isMostlyBin(data):
+ if data and strutils.isMostlyBin(data.decode()):
return get("Hex")(data)
if not data:
return "No content", []
@@ -209,7 +209,7 @@ class ViewXML(View):
p = p.getprevious()
doctype = docinfo.doctype
if prev:
- doctype += "\n".join(prev).strip()
+ doctype += "\n".join(p.decode() for p in prev).strip()
doctype = doctype.strip()
s = lxml.etree.tostring(
@@ -240,7 +240,7 @@ class ViewHTML(View):
content_types = ["text/html"]
def __call__(self, data, **metadata):
- if strutils.isXML(data):
+ if strutils.isXML(data.decode()):
parser = lxml.etree.HTMLParser(
strip_cdata=True,
remove_blank_text=True
@@ -323,7 +323,10 @@ if pyamf:
prompt = ("amf", "f")
content_types = ["application/x-amf"]
- def unpack(self, b, seen=set([])):
+ def unpack(self, b, seen=None):
+ if seen is None:
+ seen = set([])
+
if hasattr(b, "body"):
return self.unpack(b.body, seen)
if isinstance(b, DummyObject):
@@ -416,7 +419,7 @@ class ViewImage(View):
def __call__(self, data, **metadata):
try:
- img = Image.open(StringIO(data))
+ img = Image.open(BytesIO(data))
except IOError:
return None
parts = [
diff --git a/mitmproxy/controller.py b/mitmproxy/controller.py
index 898be3bc..a170d868 100644
--- a/mitmproxy/controller.py
+++ b/mitmproxy/controller.py
@@ -6,7 +6,8 @@ import threading
from six.moves import queue
from netlib import basethread
-from mitmproxy import exceptions
+
+from . import exceptions
Events = frozenset([
@@ -76,9 +77,9 @@ class Master(object):
if mtype not in Events:
raise exceptions.ControlException("Unknown event %s" % repr(mtype))
handle_func = getattr(self, mtype)
- if not hasattr(handle_func, "func_dict"):
+ if not hasattr(handle_func, "__dict__"):
raise exceptions.ControlException("Handler %s not a function" % mtype)
- if not handle_func.func_dict.get("__handler"):
+ if not handle_func.__dict__.get("__handler"):
raise exceptions.ControlException(
"Handler function %s is not decorated with controller.handler" % (
handle_func
@@ -177,7 +178,7 @@ def handler(f):
message.reply.ack()
return ret
# Mark this function as a handler wrapper
- wrapper.func_dict["__handler"] = True
+ wrapper.__dict__["__handler"] = True
return wrapper
diff --git a/mitmproxy/models/__init__.py b/mitmproxy/models/__init__.py
index ca813567..9bd19723 100644
--- a/mitmproxy/models/__init__.py
+++ b/mitmproxy/models/__init__.py
@@ -20,6 +20,6 @@ __all__ = [
"make_connect_response", "expect_continue_response",
"ClientConnection", "ServerConnection",
"Flow", "Error",
- "TCPFlow"
- "FLOW_TYPES"
+ "TCPFlow",
+ "FLOW_TYPES",
]
diff --git a/mitmproxy/platform/osx.py b/mitmproxy/platform/osx.py
index b16c1861..b5dce793 100644
--- a/mitmproxy/platform/osx.py
+++ b/mitmproxy/platform/osx.py
@@ -1,6 +1,6 @@
import subprocess
-import pf
+from . import pf
"""
Doing this the "right" way by using DIOCNATLOOK on the pf device turns out
diff --git a/mitmproxy/tnetstring.py b/mitmproxy/tnetstring.py
index 6b1c117a..f40e8ad8 100644
--- a/mitmproxy/tnetstring.py
+++ b/mitmproxy/tnetstring.py
@@ -130,7 +130,7 @@ def _rdumpq(q, size, value, encoding=None):
if value is False:
write("5:false!")
return size + 8
- if isinstance(value, (int, long)):
+ if isinstance(value, six.integer_types):
data = str(value)
ldata = len(data)
span = str(ldata)
@@ -208,7 +208,7 @@ def _gdumps(value, encoding):
yield "4:true!"
elif value is False:
yield "5:false!"
- elif isinstance(value, (int, long)):
+ elif isinstance(value, six.integer_types):
data = str(value)
yield str(len(data))
yield ":"
diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js
index b90487f3..6e685a41 100644
--- a/mitmproxy/web/static/app.js
+++ b/mitmproxy/web/static/app.js
@@ -1,5 +1,5 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.Query=exports.FlowActions=exports.SettingsActions=exports.ConnectionActions=exports.StoreCmds=exports.ActionTypes=void 0;var _jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),_dispatcher=require("./dispatcher.js"),_utils=require("./utils.js"),ActionTypes=exports.ActionTypes={CONNECTION_OPEN:"connection_open",CONNECTION_CLOSE:"connection_close",CONNECTION_ERROR:"connection_error",SETTINGS_STORE:"settings",EVENT_STORE:"events",FLOW_STORE:"flows"},StoreCmds=exports.StoreCmds={ADD:"add",UPDATE:"update",REMOVE:"remove",RESET:"reset"},ConnectionActions=exports.ConnectionActions={open:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_OPEN})},close:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_CLOSE})},error:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_ERROR})}},SettingsActions=exports.SettingsActions={update:function(e){_jquery2["default"].ajax({type:"PUT",url:"/settings",contentType:"application/json",data:JSON.stringify(e)})}},FlowActions=exports.FlowActions={accept:function(e){_jquery2["default"].post("/flows/"+e.id+"/accept")},accept_all:function(){_jquery2["default"].post("/flows/accept")},"delete":function(e){_jquery2["default"].ajax({type:"DELETE",url:"/flows/"+e.id})},duplicate:function(e){_jquery2["default"].post("/flows/"+e.id+"/duplicate")},replay:function(e){_jquery2["default"].post("/flows/"+e.id+"/replay")},revert:function(e){_jquery2["default"].post("/flows/"+e.id+"/revert")},update:function(e,t){_jquery2["default"].ajax({type:"PUT",url:"/flows/"+e.id,contentType:"application/json",data:JSON.stringify(t)})},clear:function(){_jquery2["default"].post("/clear")},download:function(){return window.location="/flows/dump"},upload:function(e){var t=new FormData;t.append("file",e),(0,_utils.fetchApi)("/flows/dump",{method:"post",body:t})}},Query=exports.Query={SEARCH:"s",HIGHLIGHT:"h",SHOW_EVENTLOG:"e"};
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.Query=exports.FlowActions=exports.ConnectionActions=exports.StoreCmds=exports.ActionTypes=void 0;var _jquery=require("jquery"),_jquery2=_interopRequireDefault(_jquery),_dispatcher=require("./dispatcher.js"),_utils=require("./utils.js"),ActionTypes=exports.ActionTypes={CONNECTION_OPEN:"connection_open",CONNECTION_CLOSE:"connection_close",CONNECTION_ERROR:"connection_error",SETTINGS_STORE:"settings",EVENT_STORE:"events",FLOW_STORE:"flows"},StoreCmds=exports.StoreCmds={ADD:"add",UPDATE:"update",REMOVE:"remove",RESET:"reset"},ConnectionActions=exports.ConnectionActions={open:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_OPEN})},close:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_CLOSE})},error:function(){_dispatcher.AppDispatcher.dispatchViewAction({type:ActionTypes.CONNECTION_ERROR})}},FlowActions=exports.FlowActions={accept:function(e){_jquery2["default"].post("/flows/"+e.id+"/accept")},accept_all:function(){_jquery2["default"].post("/flows/accept")},"delete":function(e){_jquery2["default"].ajax({type:"DELETE",url:"/flows/"+e.id})},duplicate:function(e){_jquery2["default"].post("/flows/"+e.id+"/duplicate")},replay:function(e){_jquery2["default"].post("/flows/"+e.id+"/replay")},revert:function(e){_jquery2["default"].post("/flows/"+e.id+"/revert")},update:function(e,t){_jquery2["default"].ajax({type:"PUT",url:"/flows/"+e.id,contentType:"application/json",data:JSON.stringify(t)})},clear:function(){_jquery2["default"].post("/clear")},download:function(){return window.location="/flows/dump"},upload:function(e){var t=new FormData;t.append("file",e),(0,_utils.fetchApi)("/flows/dump",{method:"post",body:t})}},Query=exports.Query={SEARCH:"s",HIGHLIGHT:"h",SHOW_EVENTLOG:"e"};
},{"./dispatcher.js":40,"./utils.js":52,"jquery":"jquery"}],2:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}var _react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_redux=require("redux"),_reactRedux=require("react-redux"),_reduxLogger=require("redux-logger"),_reduxLogger2=_interopRequireDefault(_reduxLogger),_reduxThunk=require("redux-thunk"),_reduxThunk2=_interopRequireDefault(_reduxThunk),_reactRouter=require("react-router"),_ProxyApp=require("./components/ProxyApp"),_ProxyApp2=_interopRequireDefault(_ProxyApp),_MainView=require("./components/MainView"),_MainView2=_interopRequireDefault(_MainView),_index=require("./ducks/index"),_index2=_interopRequireDefault(_index),_eventLog=require("./ducks/eventLog"),store=(0,_redux.createStore)(_index2["default"],(0,_redux.applyMiddleware)(_reduxThunk2["default"],(0,_reduxLogger2["default"])()));window.addEventListener("error",function(e){store.dispatch((0,_eventLog.addLogEntry)(e))}),document.addEventListener("DOMContentLoaded",function(){(0,_reactDom.render)(_react2["default"].createElement(_reactRedux.Provider,{store:store},_react2["default"].createElement(_reactRouter.Router,{history:_reactRouter.hashHistory},_react2["default"].createElement(_reactRouter.Redirect,{from:"/",to:"/flows"}),_react2["default"].createElement(_reactRouter.Route,{path:"/",component:_ProxyApp2["default"]},_react2["default"].createElement(_reactRouter.Route,{path:"flows",component:_MainView2["default"]}),_react2["default"].createElement(_reactRouter.Route,{path:"flows/:flowId/:detailTab",component:_MainView2["default"]})))),document.getElementById("mitmproxy"))});
@@ -53,10 +53,10 @@
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function NavAction(e){var t=e.icon,a=e.title,c=e.onClick;return _react2["default"].createElement("a",{title:a,href:"#",className:"nav-action",onClick:function(e){e.preventDefault(),c(e)}},_react2["default"].createElement("i",{className:"fa fa-fw "+t}))}function Nav(e){var t=e.flow,a=e.active,c=e.tabs,r=e.onSelectTab;return _react2["default"].createElement("nav",{className:"nav-tabs nav-tabs-sm"},c.map(function(e){return _react2["default"].createElement("a",{key:e,href:"#",className:(0,_classnames2["default"])({active:a===e}),onClick:function(t){t.preventDefault(),r(e)}},_.capitalize(e))}),_react2["default"].createElement(NavAction,{title:"[d]elete flow",icon:"fa-trash",onClick:function(){return _actions.FlowActions["delete"](t)}}),_react2["default"].createElement(NavAction,{title:"[D]uplicate flow",icon:"fa-copy",onClick:function(){return _actions.FlowActions.duplicate(t)}}),_react2["default"].createElement(NavAction,{disabled:!0,title:"[r]eplay flow",icon:"fa-repeat",onClick:function(){return _actions.FlowActions.replay(t)}}),t.intercepted&&_react2["default"].createElement(NavAction,{title:"[a]ccept intercepted flow",icon:"fa-play",onClick:function(){return _actions.FlowActions.accept(t)}}),t.modified&&_react2["default"].createElement(NavAction,{title:"revert changes to flow [V]",icon:"fa-history",onClick:function(){return _actions.FlowActions.revert(t)}}))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Nav;var _react=require("react"),_react2=_interopRequireDefault(_react),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_actions=require("../../actions.js");NavAction.propTypes={icon:_react.PropTypes.string.isRequired,title:_react.PropTypes.string.isRequired,onClick:_react.PropTypes.func.isRequired},Nav.propTypes={flow:_react.PropTypes.object.isRequired,active:_react.PropTypes.string.isRequired,tabs:_react.PropTypes.array.isRequired,onSelectTab:_react.PropTypes.func.isRequired};
},{"../../actions.js":1,"classnames":"classnames","react":"react"}],19:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function Footer(e){var a=e.settings;return _react2["default"].createElement("footer",null,a.mode&&"regular"!=a.mode&&_react2["default"].createElement("span",{className:"label label-success"},a.mode," mode"),a.intercept&&_react2["default"].createElement("span",{className:"label label-success"},"Intercept: ",a.intercept),a.showhost&&_react2["default"].createElement("span",{className:"label label-success"},"showhost"),a.no_upstream_cert&&_react2["default"].createElement("span",{className:"label label-success"},"no-upstream-cert"),a.rawtcp&&_react2["default"].createElement("span",{className:"label label-success"},"raw-tcp"),!a.http2&&_react2["default"].createElement("span",{className:"label label-success"},"no-http2"),a.anticache&&_react2["default"].createElement("span",{className:"label label-success"},"anticache"),a.anticomp&&_react2["default"].createElement("span",{className:"label label-success"},"anticomp"),a.stickyauth&&_react2["default"].createElement("span",{className:"label label-success"},"stickyauth: ",a.stickyauth),a.stickycookie&&_react2["default"].createElement("span",{className:"label label-success"},"stickycookie: ",a.stickycookie),a.stream&&_react2["default"].createElement("span",{className:"label label-success"},"stream: ",(0,_utils.formatSize)(a.stream)))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Footer;var _react=require("react"),_react2=_interopRequireDefault(_react),_utils=require("../utils.js");Footer.propTypes={settings:_react2["default"].PropTypes.object.isRequired};
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function Footer(e){var t=e.settings;return _react2["default"].createElement("footer",null,t.mode&&"regular"!=t.mode&&_react2["default"].createElement("span",{className:"label label-success"},t.mode," mode"),t.intercept&&_react2["default"].createElement("span",{className:"label label-success"},"Intercept: ",t.intercept),t.showhost&&_react2["default"].createElement("span",{className:"label label-success"},"showhost"),t.no_upstream_cert&&_react2["default"].createElement("span",{className:"label label-success"},"no-upstream-cert"),t.rawtcp&&_react2["default"].createElement("span",{className:"label label-success"},"raw-tcp"),!t.http2&&_react2["default"].createElement("span",{className:"label label-success"},"no-http2"),t.anticache&&_react2["default"].createElement("span",{className:"label label-success"},"anticache"),t.anticomp&&_react2["default"].createElement("span",{className:"label label-success"},"anticomp"),t.stickyauth&&_react2["default"].createElement("span",{className:"label label-success"},"stickyauth: ",t.stickyauth),t.stickycookie&&_react2["default"].createElement("span",{className:"label label-success"},"stickycookie: ",t.stickycookie),t.stream&&_react2["default"].createElement("span",{className:"label label-success"},"stream: ",(0,_utils.formatSize)(t.stream)))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_utils=require("../utils.js");Footer.propTypes={settings:_react2["default"].PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{settings:e.settings.settings}})(Footer);
-},{"../utils.js":52,"react":"react"}],20:[function(require,module,exports){
-"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t<e.length;t++)r[t]=e[t];return r}return Array.from(e)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_eventLog=require("../ducks/eventLog"),_MainMenu=require("./Header/MainMenu"),_MainMenu2=_interopRequireDefault(_MainMenu),_ViewMenu=require("./Header/ViewMenu"),_ViewMenu2=_interopRequireDefault(_ViewMenu),_OptionMenu=require("./Header/OptionMenu"),_OptionMenu2=_interopRequireDefault(_OptionMenu),_FileMenu=require("./Header/FileMenu"),_FileMenu2=_interopRequireDefault(_FileMenu),_FlowMenu=require("./Header/FlowMenu"),_FlowMenu2=_interopRequireDefault(_FlowMenu),_ui=require("../ducks/ui.js"),Header=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,Object.getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),_createClass(t,[{key:"handleClick",value:function(e,t){t.preventDefault(),this.props.setActiveMenu(e.title)}},{key:"render",value:function(){var e=this,r=this.props,n=r.settings,u=r.updateLocation,a=r.query,i=r.selectedFlow,o=r.activeMenu,l=[].concat(_toConsumableArray(t.entries));i&&l.push(_FlowMenu2["default"]);var c=_.find(l,function(e){return e.title==o});return _react2["default"].createElement("header",null,_react2["default"].createElement("nav",{className:"nav-tabs nav-tabs-lg"},_react2["default"].createElement(_FileMenu2["default"],null),l.map(function(t){return _react2["default"].createElement("a",{key:t.title,href:"#",className:(0,_classnames2["default"])({active:t===c}),onClick:function(r){return e.handleClick(t,r)}},t.title)})),_react2["default"].createElement("div",{className:"menu"},_react2["default"].createElement(c,{settings:n,updateLocation:u,query:a})))}}]),t}(_react.Component);Header.entries=[_MainMenu2["default"],_ViewMenu2["default"],_OptionMenu2["default"]],Header.propTypes={settings:_react.PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{selectedFlow:e.flows.selected[0],activeMenu:e.ui.activeMenu}},{setActiveMenu:_ui.setActiveMenu})(Header);
+},{"../utils.js":52,"react":"react","react-redux":"react-redux"}],20:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _toConsumableArray(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t<e.length;t++)r[t]=e[t];return r}return Array.from(e)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_eventLog=require("../ducks/eventLog"),_MainMenu=require("./Header/MainMenu"),_MainMenu2=_interopRequireDefault(_MainMenu),_ViewMenu=require("./Header/ViewMenu"),_ViewMenu2=_interopRequireDefault(_ViewMenu),_OptionMenu=require("./Header/OptionMenu"),_OptionMenu2=_interopRequireDefault(_OptionMenu),_FileMenu=require("./Header/FileMenu"),_FileMenu2=_interopRequireDefault(_FileMenu),_FlowMenu=require("./Header/FlowMenu"),_FlowMenu2=_interopRequireDefault(_FlowMenu),_ui=require("../ducks/ui.js"),Header=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,Object.getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),_createClass(t,[{key:"handleClick",value:function(e,t){t.preventDefault(),this.props.setActiveMenu(e.title)}},{key:"render",value:function(){var e=this,r=this.props,n=r.updateLocation,u=r.query,a=r.selectedFlow,i=r.activeMenu,l=[].concat(_toConsumableArray(t.entries));a&&l.push(_FlowMenu2["default"]);var o=_.find(l,function(e){return e.title==i});return _react2["default"].createElement("header",null,_react2["default"].createElement("nav",{className:"nav-tabs nav-tabs-lg"},_react2["default"].createElement(_FileMenu2["default"],null),l.map(function(t){return _react2["default"].createElement("a",{key:t.title,href:"#",className:(0,_classnames2["default"])({active:t===o}),onClick:function(r){return e.handleClick(t,r)}},t.title)})),_react2["default"].createElement("div",{className:"menu"},_react2["default"].createElement(o,{updateLocation:n,query:u})))}}]),t}(_react.Component);Header.entries=[_MainMenu2["default"],_ViewMenu2["default"],_OptionMenu2["default"]],exports["default"]=(0,_reactRedux.connect)(function(e){return{selectedFlow:e.flows.selected[0],activeMenu:e.ui.activeMenu}},{setActiveMenu:_ui.setActiveMenu})(Header);
},{"../ducks/eventLog":42,"../ducks/ui.js":46,"./Header/FileMenu":21,"./Header/FlowMenu":24,"./Header/MainMenu":25,"./Header/OptionMenu":26,"./Header/ViewMenu":27,"classnames":"classnames","react":"react","react-redux":"react-redux"}],21:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(t,n,a){return n&&e(t.prototype,n),a&&e(t,a),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_classnames=require("classnames"),_classnames2=_interopRequireDefault(_classnames),_actions=require("../../actions.js"),FileMenu=function(e){function t(e,n){_classCallCheck(this,t);var a=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,n));return a.state={show:!1},a.close=a.close.bind(a),a.onFileClick=a.onFileClick.bind(a),a.onNewClick=a.onNewClick.bind(a),a.onOpenClick=a.onOpenClick.bind(a),a.onOpenFile=a.onOpenFile.bind(a),a.onSaveClick=a.onSaveClick.bind(a),a}return _inherits(t,e),_createClass(t,[{key:"close",value:function(){this.setState({show:!1}),document.removeEventListener("click",this.close)}},{key:"onFileClick",value:function(e){e.preventDefault(),this.state.show||(document.addEventListener("click",this.close),this.setState({show:!0}))}},{key:"onNewClick",value:function(e){e.preventDefault(),confirm("Delete all flows?")&&_actions.FlowActions.clear()}},{key:"onOpenClick",value:function(e){e.preventDefault(),this.fileInput.click()}},{key:"onOpenFile",value:function(e){e.preventDefault(),e.target.files.length>0&&(_actions.FlowActions.upload(e.target.files[0]),this.fileInput.value="")}},{key:"onSaveClick",value:function(e){e.preventDefault(),_actions.FlowActions.download()}},{key:"render",value:function(){var e=this;return _react2["default"].createElement("div",{className:(0,_classnames2["default"])("dropdown pull-left",{open:this.state.show})},_react2["default"].createElement("a",{href:"#",className:"special",onClick:this.onFileClick},"mitmproxy"),_react2["default"].createElement("ul",{className:"dropdown-menu",role:"menu"},_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.onNewClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-file"}),"New")),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.onOpenClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-folder-open"}),"Open..."),_react2["default"].createElement("input",{ref:function(t){return e.fileInput=t},className:"hidden",type:"file",onChange:this.onOpenFile})),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"#",onClick:this.onSaveClick},_react2["default"].createElement("i",{className:"fa fa-fw fa-floppy-o"}),"Save...")),_react2["default"].createElement("li",{role:"presentation",className:"divider"}),_react2["default"].createElement("li",null,_react2["default"].createElement("a",{href:"http://mitm.it/",target:"_blank"},_react2["default"].createElement("i",{className:"fa fa-fw fa-external-link"}),"Install Certificates..."))))}}]),t}(_react.Component);exports["default"]=FileMenu;
@@ -71,12 +71,19 @@
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function FlowMenu(e){var t=e.flow;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_Button2["default"],{disabled:!0,title:"[r]eplay flow",text:"Replay",icon:"fa-repeat",onClick:_actions.FlowActions.replay.bind(null,t)}),_react2["default"].createElement(_Button2["default"],{title:"[D]uplicate flow",text:"Duplicate",icon:"fa-copy",onClick:_actions.FlowActions.duplicate.bind(null,t)}),_react2["default"].createElement(_Button2["default"],{title:"[d]elete flow",text:"Delete",icon:"fa-trash",onClick:_actions.FlowActions["delete"].bind(null,t)}),_react2["default"].createElement(_Button2["default"],{title:"download",text:"Download",icon:"fa-download",onClick:function(){return window.location=_utils.MessageUtils.getContentURL(t,t.response)}})),_react2["default"].createElement("div",{className:"clearfix"}))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_Button=require("../common/Button"),_Button2=_interopRequireDefault(_Button),_actions=require("../../actions.js"),_utils=require("../../flow/utils.js"),_reactRedux=require("react-redux");FlowMenu.title="Flow",FlowMenu.propTypes={flow:_react.PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{flow:e.flows.all.byId[e.flows.selected[0]]}})(FlowMenu);
},{"../../actions.js":1,"../../flow/utils.js":51,"../common/Button":34,"react":"react","react-redux":"react-redux"}],25:[function(require,module,exports){
+<<<<<<< HEAD
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _defineProperty(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_FilterInput=require("./FilterInput"),_FilterInput2=_interopRequireDefault(_FilterInput),_actions=require("../../actions.js"),_settings=require("../../ducks/settings"),_reactRedux=require("react-redux"),MainMenu=function(e){function t(e,r){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return n.onSearchChange=n.onSearchChange.bind(n),n.onHighlightChange=n.onHighlightChange.bind(n),n.onInterceptChange=n.onInterceptChange.bind(n),n}return _inherits(t,e),_createClass(t,[{key:"onSearchChange",value:function(e){this.props.updateLocation(void 0,_defineProperty({},_actions.Query.SEARCH,e))}},{key:"onHighlightChange",value:function(e){this.props.updateLocation(void 0,_defineProperty({},_actions.Query.HIGHLIGHT,e))}},{key:"onInterceptChange",value:function(e){this.props.setInterceptPattern(e)}},{key:"render",value:function(){var e=this.props,t=e.query,r=e.settings,n=t[_actions.Query.SEARCH]||"",a=t[_actions.Query.HIGHLIGHT]||"",i=r.intercept||"";return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_FilterInput2["default"],{ref:"search",placeholder:"Search",type:"search",color:"black",value:n,onChange:this.onSearchChange}),_react2["default"].createElement(_FilterInput2["default"],{ref:"highlight",placeholder:"Highlight",type:"tag",color:"hsl(48, 100%, 50%)",value:a,onChange:this.onHighlightChange}),_react2["default"].createElement(_FilterInput2["default"],{ref:"intercept",placeholder:"Intercept",type:"pause",color:"hsl(208, 56%, 53%)",value:i,onChange:this.onInterceptChange})),_react2["default"].createElement("div",{className:"clearfix"}))}}]),t}(_react.Component);MainMenu.title="Start",MainMenu.route="flows",MainMenu.propTypes={settings:_react2["default"].PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(void 0,{setInterceptPattern:_settings.setInterceptPattern})(MainMenu);
},{"../../actions.js":1,"../../ducks/settings":45,"./FilterInput":23,"react":"react","react-redux":"react-redux"}],26:[function(require,module,exports){
"use strict";function _interopRequireDefault(t){return t&&t.__esModule?t:{"default":t}}function OptionMenu(t){var e=t.settings;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_ToggleButton2["default"],{text:"showhost",checked:e.showhost,onToggle:function(){return _actions.SettingsActions.update({showhost:!e.showhost})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"no_upstream_cert",checked:e.no_upstream_cert,onToggle:function(){return _actions.SettingsActions.update({no_upstream_cert:!e.no_upstream_cert})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"rawtcp",checked:e.rawtcp,onToggle:function(){return _actions.SettingsActions.update({rawtcp:!e.rawtcp})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"http2",checked:e.http2,onToggle:function(){return _actions.SettingsActions.update({http2:!e.http2})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"anticache",checked:e.anticache,onToggle:function(){return _actions.SettingsActions.update({anticache:!e.anticache})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"anticomp",checked:e.anticomp,onToggle:function(){return _actions.SettingsActions.update({anticomp:!e.anticomp})}}),_react2["default"].createElement(_ToggleInputButton2["default"],{name:"stickyauth",placeholder:"Sticky auth filter",checked:!!e.stickyauth,txt:e.stickyauth||"",onToggleChanged:function(t){return _actions.SettingsActions.update({stickyauth:e.stickyauth?null:t})}}),_react2["default"].createElement(_ToggleInputButton2["default"],{name:"stickycookie",placeholder:"Sticky cookie filter",checked:!!e.stickycookie,txt:e.stickycookie||"",onToggleChanged:function(t){return _actions.SettingsActions.update({stickycookie:e.stickycookie?null:t})}}),_react2["default"].createElement(_ToggleInputButton2["default"],{name:"stream",placeholder:"stream...",checked:!!e.stream,txt:e.stream||"",inputType:"number",onToggleChanged:function(t){return _actions.SettingsActions.update({stream:e.stream?null:t})}})),_react2["default"].createElement("div",{className:"clearfix"}))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=OptionMenu;var _react=require("react"),_react2=_interopRequireDefault(_react),_ToggleButton=require("../common/ToggleButton"),_ToggleButton2=_interopRequireDefault(_ToggleButton),_ToggleInputButton=require("../common/ToggleInputButton"),_ToggleInputButton2=_interopRequireDefault(_ToggleInputButton),_actions=require("../../actions.js");OptionMenu.title="Options",OptionMenu.propTypes={settings:_react.PropTypes.object.isRequired};
+=======
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _defineProperty(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_FilterInput=require("./FilterInput"),_FilterInput2=_interopRequireDefault(_FilterInput),_actions=require("../../actions.js"),_settings=require("../../ducks/settings"),MainMenu=function(e){function t(e,r){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return n.onSearchChange=n.onSearchChange.bind(n),n.onHighlightChange=n.onHighlightChange.bind(n),n}return _inherits(t,e),_createClass(t,[{key:"onSearchChange",value:function(e){this.props.updateLocation(void 0,_defineProperty({},_actions.Query.SEARCH,e))}},{key:"onHighlightChange",value:function(e){this.props.updateLocation(void 0,_defineProperty({},_actions.Query.HIGHLIGHT,e))}},{key:"render",value:function(){var e=this.props,t=e.query,r=e.settings,n=e.onSettingsChange;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_FilterInput2["default"],{ref:"search",placeholder:"Search",type:"search",color:"black",value:t[_actions.Query.SEARCH]||"",onChange:this.onSearchChange}),_react2["default"].createElement(_FilterInput2["default"],{ref:"highlight",placeholder:"Highlight",type:"tag",color:"hsl(48, 100%, 50%)",value:t[_actions.Query.HIGHLIGHT]||"",onChange:this.onHighlightChange}),_react2["default"].createElement(_FilterInput2["default"],{ref:"intercept",placeholder:"Intercept",type:"pause",color:"hsl(208, 56%, 53%)",value:r.intercept||"",onChange:function(e){return n({intercept:e})}})),_react2["default"].createElement("div",{className:"clearfix"}))}}]),t}(_react.Component);MainMenu.title="Start",MainMenu.route="flows",MainMenu.propTypes={query:_react.PropTypes.object.isRequired,settings:_react.PropTypes.object.isRequired,updateLocation:_react.PropTypes.func.isRequired,onSettingsChange:_react.PropTypes.func.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{settings:e.settings.settings}},{onSettingsChange:_settings.updateSettings})(MainMenu);
-},{"../../actions.js":1,"../common/ToggleButton":36,"../common/ToggleInputButton":37,"react":"react"}],27:[function(require,module,exports){
+},{"../../actions.js":1,"../../ducks/settings":45,"./FilterInput":23,"react":"react","react-redux":"react-redux"}],26:[function(require,module,exports){
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function OptionMenu(e){var t=e.settings,n=e.onSettingsChange;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_ToggleButton2["default"],{text:"showhost",checked:t.showhost,onToggle:function(){return n({showhost:!t.showhost})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"no_upstream_cert",checked:t.no_upstream_cert,onToggle:function(){return n({no_upstream_cert:!t.no_upstream_cert})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"rawtcp",checked:t.rawtcp,onToggle:function(){return n({rawtcp:!t.rawtcp})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"http2",checked:t.http2,onToggle:function(){return n({http2:!t.http2})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"anticache",checked:t.anticache,onToggle:function(){return n({anticache:!t.anticache})}}),_react2["default"].createElement(_ToggleButton2["default"],{text:"anticomp",checked:t.anticomp,onToggle:function(){return n({anticomp:!t.anticomp})}}),_react2["default"].createElement(_ToggleInputButton2["default"],{name:"stickyauth",placeholder:"Sticky auth filter",checked:!!t.stickyauth,txt:t.stickyauth||"",onToggleChanged:function(e){return n({stickyauth:t.stickyauth?null:e})}}),_react2["default"].createElement(_ToggleInputButton2["default"],{name:"stickycookie",placeholder:"Sticky cookie filter",checked:!!t.stickycookie,txt:t.stickycookie||"",onToggleChanged:function(e){return n({stickycookie:t.stickycookie?null:e})}}),_react2["default"].createElement(_ToggleInputButton2["default"],{name:"stream",placeholder:"stream...",checked:!!t.stream,txt:t.stream||"",inputType:"number",onToggleChanged:function(e){return n({stream:t.stream?null:e})}})),_react2["default"].createElement("div",{className:"clearfix"}))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_ToggleButton=require("../common/ToggleButton"),_ToggleButton2=_interopRequireDefault(_ToggleButton),_ToggleInputButton=require("../common/ToggleInputButton"),_ToggleInputButton2=_interopRequireDefault(_ToggleInputButton),_settings=require("../../ducks/settings");OptionMenu.title="Options",OptionMenu.propTypes={settings:_react.PropTypes.object.isRequired,onSettingsChange:_react.PropTypes.func.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{settings:e.settings.settings}},{onSettingsChange:_settings.updateSettings})(OptionMenu);
+>>>>>>> origin/master
+
+},{"../../ducks/settings":45,"../common/ToggleButton":36,"../common/ToggleInputButton":37,"react":"react","react-redux":"react-redux"}],27:[function(require,module,exports){
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function ViewMenu(e){var t=e.visible,r=e.onToggle;return _react2["default"].createElement("div",null,_react2["default"].createElement("div",{className:"menu-row"},_react2["default"].createElement(_ToggleButton2["default"],{text:"Show Event Log",checked:t,onToggle:r})),_react2["default"].createElement("div",{className:"clearfix"}))}Object.defineProperty(exports,"__esModule",{value:!0});var _react=require("react"),_react2=_interopRequireDefault(_react),_reactRedux=require("react-redux"),_ToggleButton=require("../common/ToggleButton"),_ToggleButton2=_interopRequireDefault(_ToggleButton),_eventLog=require("../../ducks/eventLog");ViewMenu.title="View",ViewMenu.route="flows",ViewMenu.propTypes={visible:_react.PropTypes.bool.isRequired,onToggle:_react.PropTypes.func.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{visible:e.eventLog.visible}},{onToggle:_eventLog.toggleEventLogVisibility})(ViewMenu);
},{"../../ducks/eventLog":42,"../common/ToggleButton":36,"react":"react","react-redux":"react-redux"}],28:[function(require,module,exports){
@@ -86,9 +93,15 @@
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function Prompt(e,t){function r(e){return _lodash2["default"].map(i,"key").includes(e)}function o(e){e.stopPropagation(),e.preventDefault();var r=i.find(function(t){return _utils.Key[t.key.toUpperCase()]===e.keyCode});(r||e.keyCode===_utils.Key.ESC||e.keyCode===_utils.Key.ENTER)&&(n(k||!1),t.returnFocus())}for(var a=e.prompt,n=e.done,u=e.options,i=[],s=0;s<u.length;s++){var l=u[s];if(_lodash2["default"].isString(l)){for(var p=l;p.length>0&&r(p[0]);)p=p.substr(1);l={text:l,key:p[0]}}if(!l.text||!l.key||r(l.key))throw"invalid options";i.push(l)}return _react2["default"].createElement("div",{tabIndex:"0",onKeyDown:o,onClick:onClick,className:"prompt-dialog"},_react2["default"].createElement("div",{className:"prompt-content"},a||_react2["default"].createElement("strong",null,"Select: "),i.map(function(e){function t(t){n(e.key),t.stopPropagation()}var r=e.text.indexOf(e.key);return _react2["default"].createElement("span",{key:e.key,className:"option",onClick:t},-1!==r?e.text.substring(0,r):e.text+"(",prefix,_react2["default"].createElement("strong",{className:"text-primary"},e.key),-1!==r?e.text.substring(r+1):")")})))}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Prompt;var _react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_utils=require("../utils.js");Prompt.contextTypes={returnFocus:_react.PropTypes.func},Prompt.propTypes={options:_react.PropTypes.array.isRequired,done:_react.PropTypes.func.isRequired,prompt:_react.PropTypes.string};
},{"../utils.js":52,"lodash":"lodash","react":"react","react-dom":"react-dom"}],30:[function(require,module,exports){
+<<<<<<< HEAD
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_reactRedux=require("react-redux"),_app=require("../ducks/app"),_Header=require("./Header"),_Header2=_interopRequireDefault(_Header),_EventLog=require("./EventLog"),_EventLog2=_interopRequireDefault(_EventLog),_Footer=require("./Footer"),_Footer2=_interopRequireDefault(_Footer),_utils=require("../utils.js"),ProxyAppMain=function(e){function t(e,r){_classCallCheck(this,t);var n=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return n.focus=n.focus.bind(n),n.onKeyDown=n.onKeyDown.bind(n),n.updateLocation=n.updateLocation.bind(n),n}return _inherits(t,e),_createClass(t,[{key:"componentWillMount",value:function(){this.props.appInit()}},{key:"componentDidMount",value:function(){this.focus()}},{key:"componentWillUnmount",value:function(){this.props.appDestruct()}},{key:"getChildContext",value:function(){return{returnFocus:this.focus}}},{key:"focus",value:function(){document.activeElement.blur(),window.getSelection().removeAllRanges(),_reactDom2["default"].findDOMNode(this).focus()}},{key:"onKeyDown",value:function(e){var t=this,r=null;switch(e.keyCode){case _utils.Key.I:r="intercept";break;case _utils.Key.L:r="search";break;case _utils.Key.H:r="highlight";break;default:var n=this.refs.view;return this.refs.view.getWrappedInstance&&(n=this.refs.view.getWrappedInstance()),void(n.onMainKeyDown&&n.onMainKeyDown(e))}r&&!function(){var e=t.refs.header;e.setState({active:_Header2["default"].entries[0]},function(){e.refs.active.refs[r].select()})}(),e.preventDefault()}},{key:"updateLocation",value:function(e,t){void 0===e&&(e=this.props.location.pathname);var r=this.props.location.query,n=!0,o=!1,a=void 0;try{for(var i,u=Object.keys(t||{})[Symbol.iterator]();!(n=(i=u.next()).done);n=!0){var c=i.value;r[c]=t[c]||void 0}}catch(s){o=!0,a=s}finally{try{!n&&u["return"]&&u["return"]()}finally{if(o)throw a}}this.context.router.replace({pathname:e,query:r})}},{key:"getQuery",value:function(){return _lodash2["default"].clone(this.props.location.query)}},{key:"render",value:function(){var e=this.props,t=e.showEventLog,r=e.location,n=e.children,o=e.settings,a=this.getQuery();return _react2["default"].createElement("div",{id:"container",tabIndex:"0",onKeyDown:this.onKeyDown},_react2["default"].createElement(_Header2["default"],{ref:"header",settings:o,updateLocation:this.updateLocation,query:a}),_react2["default"].cloneElement(n,{ref:"view",location:r,query:a,updateLocation:this.updateLocation}),t&&_react2["default"].createElement(_EventLog2["default"],{key:"eventlog"}),_react2["default"].createElement(_Footer2["default"],{settings:o}))}}]),t}(_react.Component);ProxyAppMain.childContextTypes={returnFocus:_react.PropTypes.func.isRequired},ProxyAppMain.contextTypes={router:_react.PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{showEventLog:e.eventLog.visible,settings:e.settings.settings}},{appInit:_app.init,appDestruct:_app.destruct})(ProxyAppMain);
},{"../ducks/app":41,"../utils.js":52,"./EventLog":8,"./Footer":19,"./Header":20,"lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux"}],31:[function(require,module,exports){
+=======
+"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var o=t[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,r,o){return r&&e(t.prototype,r),o&&e(t,o),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_lodash=require("lodash"),_lodash2=_interopRequireDefault(_lodash),_reactRedux=require("react-redux"),_Header=require("./Header"),_Header2=_interopRequireDefault(_Header),_EventLog=require("./EventLog"),_EventLog2=_interopRequireDefault(_EventLog),_Footer=require("./Footer"),_Footer2=_interopRequireDefault(_Footer),_utils=require("../utils.js"),ProxyAppMain=function(e){function t(e,r){_classCallCheck(this,t);var o=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e,r));return o.focus=o.focus.bind(o),o.onKeyDown=o.onKeyDown.bind(o),o.updateLocation=o.updateLocation.bind(o),o}return _inherits(t,e),_createClass(t,[{key:"updateLocation",value:function(e,t){void 0===e&&(e=this.props.location.pathname);var r=this.props.location.query,o=!0,n=!1,a=void 0;try{for(var i,u=Object.keys(t||{})[Symbol.iterator]();!(o=(i=u.next()).done);o=!0){var c=i.value;r[c]=t[c]||void 0}}catch(l){n=!0,a=l}finally{try{!o&&u["return"]&&u["return"]()}finally{if(n)throw a}}this.context.router.replace({pathname:e,query:r})}},{key:"getQuery",value:function(){return _lodash2["default"].clone(this.props.location.query)}},{key:"componentDidMount",value:function(){this.focus()}},{key:"getChildContext",value:function(){return{returnFocus:this.focus}}},{key:"focus",value:function(){document.activeElement.blur(),window.getSelection().removeAllRanges(),_reactDom2["default"].findDOMNode(this).focus()}},{key:"onKeyDown",value:function(e){var t=this,r=null;switch(e.keyCode){case _utils.Key.I:r="intercept";break;case _utils.Key.L:r="search";break;case _utils.Key.H:r="highlight";break;default:var o=this.refs.view;return this.refs.view.getWrappedInstance&&(o=this.refs.view.getWrappedInstance()),void(o.onMainKeyDown&&o.onMainKeyDown(e))}r&&!function(){var e=t.refs.header;e.setState({active:_Header2["default"].entries[0]},function(){e.refs.active.refs[r].select()})}(),e.preventDefault()}},{key:"render",value:function(){var e=this.props,t=e.showEventLog,r=e.location,o=e.children,n=this.getQuery();return _react2["default"].createElement("div",{id:"container",tabIndex:"0",onKeyDown:this.onKeyDown},_react2["default"].createElement(_Header2["default"],{ref:"header",updateLocation:this.updateLocation,query:n}),_react2["default"].cloneElement(o,{ref:"view",location:r,query:n,updateLocation:this.updateLocation}),t&&_react2["default"].createElement(_EventLog2["default"],{key:"eventlog"}),_react2["default"].createElement(_Footer2["default"],null))}}]),t}(_react.Component);ProxyAppMain.childContextTypes={returnFocus:_react.PropTypes.func.isRequired},ProxyAppMain.contextTypes={router:_react.PropTypes.object.isRequired},exports["default"]=(0,_reactRedux.connect)(function(e){return{showEventLog:e.eventLog.visible}})(ProxyAppMain);
+
+},{"../utils.js":52,"./EventLog":8,"./Footer":19,"./Header":20,"lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux"}],31:[function(require,module,exports){
+>>>>>>> origin/master
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(exports,"__esModule",{value:!0});var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o])}return e},_createClass=function(){function e(e,t){for(var r=0;r<t.length;r++){var o=t[r];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}return function(t,r,o){return r&&e(t.prototype,r),o&&e(t,o),t}}(),_react=require("react"),_react2=_interopRequireDefault(_react),_reactDom=require("react-dom"),_reactDom2=_interopRequireDefault(_reactDom),_ValidateEditor=require("./ValueEditor/ValidateEditor"),_ValidateEditor2=_interopRequireDefault(_ValidateEditor),ValueEditor=function(e){function t(e){_classCallCheck(this,t);var r=_possibleConstructorReturn(this,Object.getPrototypeOf(t).call(this,e));return r.focus=r.focus.bind(r),r}return _inherits(t,e),_createClass(t,[{key:"render",value:function(){var e=this,t=this.props.inline?"span":"div";return _react2["default"].createElement(_ValidateEditor2["default"],_extends({},this.props,{onStop:function(){return e.context.returnFocus()},tag:t}))}},{key:"focus",value:function(){_reactDom2["default"].findDOMNode(this).focus()}}]),t}(_react.Component);ValueEditor.contextTypes={returnFocus:_react.PropTypes.func},ValueEditor.propTypes={content:_react.PropTypes.string.isRequired,onDone:_react.PropTypes.func.isRequired,inline:_react.PropTypes.bool},exports["default"]=ValueEditor;
},{"./ValueEditor/ValidateEditor":33,"react":"react","react-dom":"react-dom"}],32:[function(require,module,exports){
@@ -116,6 +129,12 @@
"use strict";function calcVScroll(t){if(!t)return{start:0,end:0,paddingTop:0,paddingBottom:0};var e=t.itemCount,o=t.rowHeight,r=t.viewportTop,a=t.viewportHeight,i=t.itemHeights,l=r+a,n=0,c=0,d=0,p=0;if(i)for(var h=0,s=0;e>h;h++){var m=i[h]||o;r>=s&&h%2===0&&(d=s,n=h),l>=s?c=h+1:p+=m,s+=m}else n=-2&Math.max(0,Math.floor(r/o)-1),c=Math.min(e,n+Math.ceil(a/o)+2),d=Math.min(n,e)*o,p=Math.max(0,e-c)*o;return{start:n,end:c,paddingTop:d,paddingBottom:p}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.calcVScroll=calcVScroll;
},{}],40:[function(require,module,exports){
+<<<<<<< HEAD
+=======
+"use strict";function _interopRequireWildcard(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t["default"]=e,t}function Connection(e,t){"/"===e[0]&&(e=location.origin.replace("http","ws")+e);var n=new WebSocket(e);return n.onopen=function(){t(webSocketActions.connected()),t(settingsActions.fetchSettings()),t(flowActions.fetchFlows()).then(function(){console.log("flows are loaded now"),_actions.ConnectionActions.open()}),t(eventLogActions.fetchLogEntries())},n.onmessage=function(e){var n=JSON.parse(e.data);switch(_dispatcher.AppDispatcher.dispatchServerAction(n),n.type){case eventLogActions.UPDATE_LOG:return t(eventLogActions.updateLogEntries(n));case flowActions.UPDATE_FLOWS:return t(flowActions.updateFlows(n));case settingsActions.UPDATE_SETTINGS:return t(settingsActions.updateSettings(n));default:console.warn("unknown message",n)}},n.onerror=function(){_actions.ConnectionActions.error(),t(eventLogActions.addLogEntry("WebSocket connection error."))},n.onclose=function(){_actions.ConnectionActions.close(),t(eventLogActions.addLogEntry("WebSocket connection closed.")),t(webSocketActions.disconnected())},n}Object.defineProperty(exports,"__esModule",{value:!0}),exports["default"]=Connection;var _actions=require("./actions.js"),_dispatcher=require("./dispatcher.js"),_websocket=require("./ducks/websocket"),webSocketActions=_interopRequireWildcard(_websocket),_eventLog=require("./ducks/eventLog"),eventLogActions=_interopRequireWildcard(_eventLog),_flows=require("./ducks/flows"),flowActions=_interopRequireWildcard(_flows),_settings=require("./ducks/settings"),settingsActions=_interopRequireWildcard(_settings);
+
+},{"./actions.js":1,"./dispatcher.js":41,"./ducks/eventLog":42,"./ducks/flows":43,"./ducks/settings":45,"./ducks/websocket":49}],41:[function(require,module,exports){
+>>>>>>> origin/master
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.AppDispatcher=void 0;var _flux=require("flux"),_flux2=_interopRequireDefault(_flux),PayloadSources={VIEW:"view",SERVER:"server"},AppDispatcher=exports.AppDispatcher=new _flux2["default"].Dispatcher;AppDispatcher.dispatchViewAction=function(e){e.source=PayloadSources.VIEW,this.dispatch(e)},AppDispatcher.dispatchServerAction=function(e){e.source=PayloadSources.SERVER,this.dispatch(e)};
},{"flux":"flux"}],41:[function(require,module,exports){
@@ -131,7 +150,11 @@
"use strict";function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(exports,"__esModule",{value:!0});var _redux=require("redux"),_eventLog=require("./eventLog"),_eventLog2=_interopRequireDefault(_eventLog),_websocket=require("./websocket"),_websocket2=_interopRequireDefault(_websocket),_flows=require("./flows"),_flows2=_interopRequireDefault(_flows),_settings=require("./settings"),_settings2=_interopRequireDefault(_settings),_ui=require("./ui"),_ui2=_interopRequireDefault(_ui),rootReducer=(0,_redux.combineReducers)({eventLog:_eventLog2["default"],websocket:_websocket2["default"],flows:_flows2["default"],settings:_settings2["default"],ui:_ui2["default"]});exports["default"]=rootReducer;
},{"./eventLog":42,"./flows":43,"./settings":45,"./ui":46,"./websocket":49,"redux":"redux"}],45:[function(require,module,exports){
+<<<<<<< HEAD
"use strict";function _toConsumableArray(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e<t.length;e++)r[e]=t[e];return r}return Array.from(t)}function reducer(){var t=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],e=arguments[1];switch(e.type){case REQUEST_SETTINGS:return _extends({},t,{isFetching:!0});case RECEIVE_SETTINGS:var r={settings:e.settings,isFetching:!1,actionsDuringFetch:[]},n=!0,s=!1,i=void 0;try{for(var u,o=t.actionsDuringFetch[Symbol.iterator]();!(n=(u=o.next()).done);n=!0)e=u.value,r=reducer(r,e)}catch(E){s=!0,i=E}finally{try{!n&&o["return"]&&o["return"]()}finally{if(s)throw i}}return r;case UPDATE_SETTINGS:return t.isFetching?_extends({},t,{actionsDuringFetch:[].concat(_toConsumableArray(t.actionsDuringFetch),[e])}):_extends({},t,{settings:_extends({},t.settings,e.settings)});default:return t}}function updateSettings(t){return"update"===t.cmd?{type:UPDATE_SETTINGS,settings:t.data}:void console.error("unknown settings update",t)}function fetchSettings(){return function(t){return t({type:REQUEST_SETTINGS}),(0,_utils.fetchApi)("/settings").then(function(t){return t.json()}).then(function(e){return t({type:RECEIVE_SETTINGS,settings:e.data})})}}function setInterceptPattern(t){return function(e){return _utils.fetchApi.put("/settings",{intercept:t})}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.UPDATE_SETTINGS=exports.RECEIVE_SETTINGS=exports.REQUEST_SETTINGS=void 0;var _extends=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var r=arguments[e];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n])}return t};exports["default"]=reducer,exports.updateSettings=updateSettings,exports.fetchSettings=fetchSettings,exports.setInterceptPattern=setInterceptPattern;var _utils=require("../utils"),REQUEST_SETTINGS=exports.REQUEST_SETTINGS="REQUEST_SETTINGS",RECEIVE_SETTINGS=exports.RECEIVE_SETTINGS="RECEIVE_SETTINGS",UPDATE_SETTINGS=exports.UPDATE_SETTINGS="UPDATE_SETTINGS",defaultState={settings:{},isFetching:!1,actionsDuringFetch:[]};
+=======
+"use strict";function _toConsumableArray(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e<t.length;e++)n[e]=t[e];return n}return Array.from(t)}function reducer(){var t=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],e=arguments[1];switch(e.type){case REQUEST_SETTINGS:return _extends({},t,{isFetching:!0});case RECEIVE_SETTINGS:var n={settings:e.settings,isFetching:!1,actionsDuringFetch:[]},r=!0,s=!1,i=void 0;try{for(var u,E=t.actionsDuringFetch[Symbol.iterator]();!(r=(u=E.next()).done);r=!0)e=u.value,n=reducer(n,e)}catch(S){s=!0,i=S}finally{try{!r&&E["return"]&&E["return"]()}finally{if(s)throw i}}return n;case UPDATE_SETTINGS:return t.isFetching?_extends({},t,{actionsDuringFetch:[].concat(_toConsumableArray(t.actionsDuringFetch),[e])}):_extends({},t,{settings:_extends({},t.settings,e.settings)});default:return t}}function updateSettings(t){return"update"===t.cmd?{type:UPDATE_SETTINGS,settings:t.data}:void console.error("unknown settings update",t)}function fetchSettings(){return function(t){return t({type:REQUEST_SETTINGS}),(0,_utils.fetchApi)("/settings").then(function(t){return t.json()}).then(function(e){return t({type:RECEIVE_SETTINGS,settings:e.data})})}}function updateSettings(t){return _utils.fetchApi.put("/settings",t),{type:SET_INTERCEPT}}Object.defineProperty(exports,"__esModule",{value:!0}),exports.UPDATE_SETTINGS=exports.RECEIVE_SETTINGS=exports.REQUEST_SETTINGS=void 0;var _extends=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(t[r]=n[r])}return t};exports["default"]=reducer,exports.updateSettings=updateSettings,exports.fetchSettings=fetchSettings,exports.updateSettings=updateSettings;var _utils=require("../utils"),REQUEST_SETTINGS=exports.REQUEST_SETTINGS="REQUEST_SETTINGS",RECEIVE_SETTINGS=exports.RECEIVE_SETTINGS="RECEIVE_SETTINGS",UPDATE_SETTINGS=exports.UPDATE_SETTINGS="UPDATE_SETTINGS",defaultState={settings:{},isFetching:!1,actionsDuringFetch:[]};
+>>>>>>> origin/master
},{"../utils":52}],46:[function(require,module,exports){
"use strict";function reducer(){var e=arguments.length<=0||void 0===arguments[0]?defaultState:arguments[0],t=arguments[1];switch(t.type){case SET_ACTIVE_MENU:return _extends({},e,{activeMenu:t.activeMenu});case _flows.SELECT_FLOW:var r=t.flowId&&!t.currentSelection,n=!t.flowId&&t.currentSelection;return r?_extends({},e,{activeMenu:"Flow"}):n&&"Flow"===e.activeMenu?_extends({},e,{activeMenu:"Start"}):e;default:return e}}function setActiveMenu(e){return{type:SET_ACTIVE_MENU,activeMenu:e}}Object.defineProperty(exports,"__esModule",{value:!0});var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e};exports["default"]=reducer,exports.setActiveMenu=setActiveMenu;var _flows=require("./flows"),SET_ACTIVE_MENU="SET_ACTIVE_MENU",defaultState={activeMenu:"Start"};
diff --git a/test/mitmproxy/completion/bbb/Readme.md b/test/mitmproxy/completion/bbb/Readme.md
new file mode 100644
index 00000000..ac534722
--- /dev/null
+++ b/test/mitmproxy/completion/bbb/Readme.md
@@ -0,0 +1,2 @@
+
+This empty directory has been added so that we can hit [this line](https://codecov.io/gh/mitmproxy/mitmproxy/src/ba13fda10d3065a0c8dfd95d55680675b3bf08c2/mitmproxy/console/pathedit.py#L43) while testing pathedit completion.
diff --git a/test/mitmproxy/console/test_pathedit.py b/test/mitmproxy/console/test_pathedit.py
index 107a48ac..ff6ef846 100644
--- a/test/mitmproxy/console/test_pathedit.py
+++ b/test/mitmproxy/console/test_pathedit.py
@@ -2,6 +2,8 @@ import os
from os.path import normpath
from mitmproxy.console import pathedit
+from mock import patch
+
from .. import tutils
@@ -47,3 +49,25 @@ class TestPathCompleter:
s = "thisisatotallynonexistantpathforsure"
assert c.complete(s) == s
assert c.final == s
+
+
+class TestPathEdit():
+
+ def test_keypress(self):
+
+ pe = pathedit.PathEdit()
+
+ with patch('urwid.widget.Edit.get_edit_text') as get_text, \
+ patch('urwid.widget.Edit.set_edit_text') as set_text:
+
+ cd = tutils.test_data.path("completion")
+ get_text.return_value = os.path.join(cd, "a")
+
+ # Pressing tab should set completed path
+ pe.keypress((1,), "tab")
+ set_text_called_with = set_text.call_args[0][0]
+ assert set_text_called_with.endswith(normpath("/completion/aaa"))
+
+ # Pressing any other key should reset
+ pe.keypress((1,), "a")
+ assert pe.lookup is None
diff --git a/test/mitmproxy/mastertest.py b/test/mitmproxy/mastertest.py
index 4d04f337..9e726a32 100644
--- a/test/mitmproxy/mastertest.py
+++ b/test/mitmproxy/mastertest.py
@@ -1,7 +1,8 @@
-import tutils
-import netlib.tutils
import mock
+from . import tutils
+import netlib.tutils
+
from mitmproxy import flow, proxy, models
diff --git a/test/mitmproxy/test_cmdline.py b/test/mitmproxy/test_cmdline.py
index e75b7baf..4fe2cf94 100644
--- a/test/mitmproxy/test_cmdline.py
+++ b/test/mitmproxy/test_cmdline.py
@@ -39,11 +39,11 @@ def test_parse_replace_hook():
def test_parse_server_spec():
tutils.raises("Invalid server specification", cmdline.parse_server_spec, "")
assert cmdline.parse_server_spec(
- "http://foo.com:88") == ("http", ("foo.com", 88))
+ "http://foo.com:88") == (b"http", (b"foo.com", 88))
assert cmdline.parse_server_spec(
- "http://foo.com") == ("http", ("foo.com", 80))
+ "http://foo.com") == (b"http", (b"foo.com", 80))
assert cmdline.parse_server_spec(
- "https://foo.com") == ("https", ("foo.com", 443))
+ "https://foo.com") == (b"https", (b"foo.com", 443))
tutils.raises(
"Invalid server specification",
cmdline.parse_server_spec,
@@ -59,9 +59,9 @@ def test_parse_upstream_auth():
tutils.raises("Invalid upstream auth specification", cmdline.parse_upstream_auth, ":")
tutils.raises("Invalid upstream auth specification", cmdline.parse_upstream_auth, ":test")
assert cmdline.parse_upstream_auth(
- "test:test") == "Basic" + " " + base64.b64encode("test:test")
+ "test:test") == b"Basic" + b" " + base64.b64encode(b"test:test")
assert cmdline.parse_upstream_auth(
- "test:") == "Basic" + " " + base64.b64encode("test:")
+ "test:") == b"Basic" + b" " + base64.b64encode(b"test:")
def test_parse_setheaders():
@@ -124,7 +124,7 @@ def test_common():
opts.replace_file = [("/foo/bar/%s" % p)]
v = cmdline.get_common_options(opts)["replacements"]
assert len(v) == 1
- assert v[0][2].strip() == "replacecontents"
+ assert v[0][2].strip() == b"replacecontents"
def test_mitmproxy():
diff --git a/test/mitmproxy/test_contentview.py b/test/mitmproxy/test_contentview.py
index 667a36fe..52fceeac 100644
--- a/test/mitmproxy/test_contentview.py
+++ b/test/mitmproxy/test_contentview.py
@@ -23,37 +23,37 @@ class TestContentView:
def test_view_auto(self):
v = cv.ViewAuto()
f = v(
- "foo",
+ b"foo",
headers=Headers()
)
assert f[0] == "Raw"
f = v(
- "<html></html>",
+ b"<html></html>",
headers=Headers(content_type="text/html")
)
assert f[0] == "HTML"
f = v(
- "foo",
+ b"foo",
headers=Headers(content_type="text/flibble")
)
assert f[0] == "Raw"
f = v(
- "<xml></xml>",
+ b"<xml></xml>",
headers=Headers(content_type="text/flibble")
)
assert f[0].startswith("XML")
f = v(
- "",
+ b"",
headers=Headers()
)
assert f[0] == "No content"
f = v(
- "",
+ b"",
headers=Headers(),
query=multidict.MultiDict([("foo", "bar")]),
)
@@ -69,29 +69,29 @@ class TestContentView:
def test_view_html(self):
v = cv.ViewHTML()
- s = "<html><br><br></br><p>one</p></html>"
+ s = b"<html><br><br></br><p>one</p></html>"
assert v(s)
- s = "gobbledygook"
+ s = b"gobbledygook"
assert not v(s)
def test_view_html_outline(self):
v = cv.ViewHTMLOutline()
- s = "<html><br><br></br><p>one</p></html>"
+ s = b"<html><br><br></br><p>one</p></html>"
assert v(s)
def test_view_json(self):
cv.VIEW_CUTOFF = 100
v = cv.ViewJSON()
- assert v("{}")
- assert not v("{")
- assert v("[1, 2, 3, 4, 5]")
+ assert v(b"{}")
+ assert not v(b"{")
+ assert v(b"[1, 2, 3, 4, 5]")
def test_view_xml(self):
v = cv.ViewXML()
- assert v("<foo></foo>")
- assert not v("<foo>")
- s = """<?xml version="1.0" encoding="UTF-8"?>
+ assert v(b"<foo></foo>")
+ assert not v(b"<foo>")
+ s = b"""<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet title="XSL_formatting"?>
<rss
xmlns:media="http://search.yahoo.com/mrss/"
@@ -103,7 +103,7 @@ class TestContentView:
def test_view_raw(self):
v = cv.ViewRaw()
- assert v("foo")
+ assert v(b"foo")
def test_view_javascript(self):
v = cv.ViewJavaScript()
@@ -133,27 +133,27 @@ class TestContentView:
def test_view_hex(self):
v = cv.ViewHex()
- assert v("foo")
+ assert v(b"foo")
def test_view_image(self):
v = cv.ViewImage()
p = tutils.test_data.path("data/image.png")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
p = tutils.test_data.path("data/image.gif")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
p = tutils.test_data.path("data/image-err1.jpg")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
p = tutils.test_data.path("data/image.ico")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
- assert not v("flibble")
+ assert not v(b"flibble")
def test_view_multipart(self):
view = cv.ViewMultipart()
- v = """
+ v = b"""
--AaB03x
Content-Disposition: form-data; name="submit-name"
@@ -182,21 +182,21 @@ Larry
def test_get_content_view(self):
r = cv.get_content_view(
cv.get("Raw"),
- "[1, 2, 3]",
+ b"[1, 2, 3]",
headers=Headers(content_type="application/json")
)
assert "Raw" in r[0]
r = cv.get_content_view(
cv.get("Auto"),
- "[1, 2, 3]",
+ b"[1, 2, 3]",
headers=Headers(content_type="application/json")
)
assert r[0] == "JSON"
r = cv.get_content_view(
cv.get("Auto"),
- "[1, 2",
+ b"[1, 2",
headers=Headers(content_type="application/json")
)
assert "Raw" in r[0]
@@ -205,13 +205,13 @@ Larry
ContentViewException,
cv.get_content_view,
cv.get("AMF"),
- "[1, 2",
+ b"[1, 2",
headers=Headers()
)
r = cv.get_content_view(
cv.get("Auto"),
- encoding.encode('gzip', "[1, 2, 3]"),
+ encoding.encode('gzip', b"[1, 2, 3]"),
headers=Headers(
content_type="application/json",
content_encoding="gzip"
@@ -222,7 +222,7 @@ Larry
r = cv.get_content_view(
cv.get("XML"),
- encoding.encode('gzip', "[1, 2, 3]"),
+ encoding.encode('gzip', b"[1, 2, 3]"),
headers=Headers(
content_type="application/json",
content_encoding="gzip"
@@ -252,22 +252,22 @@ if pyamf:
v = cv.ViewAMF()
p = tutils.test_data.path("data/amf01")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
p = tutils.test_data.path("data/amf02")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
def test_view_amf_response():
v = cv.ViewAMF()
p = tutils.test_data.path("data/amf03")
- assert v(file(p, "rb").read())
+ assert v(open(p, "rb").read())
if cv.ViewProtobuf.is_available():
def test_view_protobuf_request():
v = cv.ViewProtobuf()
p = tutils.test_data.path("data/protobuf01")
- content_type, output = v(file(p, "rb").read())
+ content_type, output = v(open(p, "rb").read())
assert content_type == "Protobuf"
assert output.next()[0][1] == '1: "3bbc333c-e61c-433b-819a-0b9a8cc103b8"'
@@ -277,7 +277,7 @@ def test_get_by_shortcut():
def test_pretty_json():
- assert cv.pretty_json('{"foo": 1}')
- assert not cv.pretty_json("moo")
+ assert cv.pretty_json(b'{"foo": 1}')
+ assert not cv.pretty_json(b"moo")
assert cv.pretty_json(b'{"foo" : "\xe4\xb8\x96\xe7\x95\x8c"}') # utf8 with chinese characters
assert not cv.pretty_json(b'{"foo" : "\xFF"}')
diff --git a/test/mitmproxy/test_custom_contentview.py b/test/mitmproxy/test_custom_contentview.py
index 479b0b43..889fb8b3 100644
--- a/test/mitmproxy/test_custom_contentview.py
+++ b/test/mitmproxy/test_custom_contentview.py
@@ -40,7 +40,7 @@ def test_custom_views():
cv.remove(view_obj)
r = cv.get_content_view(
cv.get("Auto"),
- "[1, 2, 3]",
+ b"[1, 2, 3]",
headers=Headers(
content_type="text/none"
)
diff --git a/tox.ini b/tox.ini
index 1c48b91f..4837d5b5 100644
--- a/tox.ini
+++ b/tox.ini
@@ -7,7 +7,7 @@ deps =
codecov>=2.0.5
passenv = CI TRAVIS_BUILD_ID TRAVIS TRAVIS_BRANCH TRAVIS_JOB_NUMBER TRAVIS_PULL_REQUEST TRAVIS_JOB_ID TRAVIS_REPO_SLUG TRAVIS_COMMIT
setenv =
- PY3TESTS = test/netlib test/pathod/ test/mitmproxy/script
+ PY3TESTS = test/netlib test/pathod/ test/mitmproxy/script test/mitmproxy/test_contentview.py test/mitmproxy/test_custom_contentview.py test/mitmproxy/test_app.py test/mitmproxy/test_controller.py test/mitmproxy/test_fuzzing.py test/mitmproxy/test_script.py test/mitmproxy/test_web_app.py test/mitmproxy/test_utils.py test/mitmproxy/test_stateobject.py test/mitmproxy/test_cmdline.py
[testenv:py27]
commands =
diff --git a/web/package.json b/web/package.json
index 7ace808a..70785dfc 100644
--- a/web/package.json
+++ b/web/package.json
@@ -53,6 +53,7 @@
"gulp-sourcemaps": "^1.6.0",
"gulp-util": "^3.0.7",
"jest": "^12.1.1",
+ "react-addons-test-utils": "^15.1.0",
"uglifyify": "^3.0.1",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0",
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 = {