From 8b998cfbeace0777293f3cef804c1bf239758273 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 10:27:48 -0500 Subject: Implemented basic marking of flows - Press m to toggle flow mark - Flow mark is set in libmproxy/console/common.py. Currently set to "===" --- libmproxy/console/common.py | 7 +++++++ libmproxy/console/flowlist.py | 8 ++++++++ libmproxy/protocol/primitives.py | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index e5bebf7f..584b7475 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -115,6 +115,7 @@ def fcol(s, attr): if urwid.util.detected_encoding: SYMBOL_REPLAY = u"\u21ba" SYMBOL_RETURN = u"\u2190" + SYMBOL_MARK = "===" else: SYMBOL_REPLAY = u"[r]" SYMBOL_RETURN = u"<-" @@ -133,6 +134,10 @@ def raw_format_flow(f, focus, extended, padding): ) else: req.append(fcol(">>" if focus else " ", "focus")) + + if f["marked"]: + req.append(fcol(SYMBOL_MARK, "mark")) + if f["req_is_replay"]: req.append(fcol(SYMBOL_REPLAY, "replay")) req.append(fcol(f["req_method"], "method")) @@ -384,6 +389,8 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2): err_msg = f.error.msg if f.error else None, resp_code = f.response.code if f.response else None, + + marked = f.marked, ) if f.response: if f.response.content: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 39245984..8bb6f87a 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -17,6 +17,7 @@ def _mkhelp(): ("F", "toggle follow flow list"), ("l", "set limit filter pattern"), ("L", "load saved flows"), + ("m", "toggle flow mark"), ("n", "create a new request"), ("P", "copy flow to clipboard"), ("r", "replay request"), @@ -177,6 +178,13 @@ class ConnectionItem(urwid.WidgetWrap): elif key == "D": f = self.master.duplicate_flow(self.flow) self.master.view_flow(f) + elif key == "m": + self.flow.toggle_mark() + signals.flowlist_change.send(self) + if self.flow.marked: + signals.status_message.send(message="Flow is now marked") + else: + signals.status_message.send(message="Flow is now not marked") elif key == "r": r = self.master.replay_request(self.flow) if r: diff --git a/libmproxy/protocol/primitives.py b/libmproxy/protocol/primitives.py index 2f8ea3e0..1d2389c3 100644 --- a/libmproxy/protocol/primitives.py +++ b/libmproxy/protocol/primitives.py @@ -77,6 +77,7 @@ class Flow(stateobject.StateObject): """@type: bool""" self._backup = None self.reply = None + self.marked = False _stateobject_attributes = dict( id=str, @@ -165,6 +166,12 @@ class Flow(stateobject.StateObject): self.intercepted = False self.reply() master.handle_accept_intercept(self) + + def toggle_mark(self): + if self.marked: + self.marked = False + else: + self.marked = True class ProtocolHandler(object): -- cgit v1.2.3 From e53a2426c153337fe25ef6dd13059cf2c4d0ab0b Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 11:40:03 -0500 Subject: Marked flows not deleted on clear all Marked flows survive a clear all unless all current flows are marked. Bug: They don't show up until another flow is added --- libmproxy/console/flowlist.py | 4 ---- libmproxy/flow.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 8bb6f87a..f7835419 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -181,10 +181,6 @@ class ConnectionItem(urwid.WidgetWrap): elif key == "m": self.flow.toggle_mark() signals.flowlist_change.send(self) - if self.flow.marked: - signals.status_message.send(message="Flow is now marked") - else: - signals.status_message.send(message="Flow is now not marked") elif key == "r": r = self.master.replay_request(self.flow) if r: diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 1a052f51..65aa2909 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -494,8 +494,19 @@ class FlowStore(FlowList): self._recalculate_views() def _clear(self): + marked_flows = [] + for f in self._list: + if f.marked: + marked_flows.append(f) + if len(marked_flows) == len(self._list): + marked_flows = [] + self._list = [] self._set = set() + + for f in marked_flows: + self._add(f) + self._recalculate_views() def _recalculate_views(self): -- cgit v1.2.3 From a34eeb9a281fa4cd036d2ede096dbe44f78ab1d2 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 11:49:23 -0500 Subject: Fixed console rendering bug Clearing all flows now works properly --- libmproxy/console/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 052ac7dd..cbcba52f 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -100,9 +100,12 @@ class ConsoleState(flow.State): return ret def clear(self): - self.focus = None super(ConsoleState, self).clear() - + if len(self.flows.views) == 0: + self.focus = None + else: + self.focus = 0 + self.set_focus(self.focus) class Options(object): attributes = [ -- cgit v1.2.3 From 13e71eba100a36a9464b0f09b5f6dbfcbec17833 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 12:02:15 -0500 Subject: Changed symbols and colors Added a better symbol for the mark, and changed the color to red. This helps it stand out more easily. --- libmproxy/console/common.py | 3 ++- libmproxy/console/palettes.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 584b7475..51911746 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -115,10 +115,11 @@ def fcol(s, attr): if urwid.util.detected_encoding: SYMBOL_REPLAY = u"\u21ba" SYMBOL_RETURN = u"\u2190" - SYMBOL_MARK = "===" + SYMBOL_MARK = u"[M] \u2192" else: SYMBOL_REPLAY = u"[r]" SYMBOL_RETURN = u"<-" + SYMBOL_MARK = "[M] ==>" def raw_format_flow(f, focus, extended, padding): diff --git a/libmproxy/console/palettes.py b/libmproxy/console/palettes.py index ea3d1b62..d897a0a2 100644 --- a/libmproxy/console/palettes.py +++ b/libmproxy/console/palettes.py @@ -24,7 +24,7 @@ class Palette: 'method', 'focus', 'code_200', 'code_300', 'code_400', 'code_500', 'code_other', 'error', - 'header', 'highlight', 'intercept', 'replay', + 'header', 'highlight', 'intercept', 'replay', 'mark', # Hex view 'offset', @@ -104,6 +104,7 @@ class LowDark(Palette): highlight = ('white,bold', 'default'), intercept = ('brown', 'default'), replay = ('light green', 'default'), + mark = ('light red', 'default'), # Hex view offset = ('dark cyan', 'default'), @@ -167,6 +168,7 @@ class LowLight(Palette): highlight = ('black,bold', 'default'), intercept = ('brown', 'default'), replay = ('dark green', 'default'), + mark = ('dark red', 'default'), # Hex view offset = ('dark blue', 'default'), -- cgit v1.2.3 From 122ee88021176c6bd2a19bb34ede86809cef66b9 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 12:52:15 -0500 Subject: Unmark duplicated flows If a marked flow is duplicated, the duplicate will now be unmarked --- libmproxy/flow.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 65aa2909..0dffc8d3 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -815,7 +815,9 @@ class FlowMaster(controller.Master): return super(FlowMaster, self).tick(q, timeout) def duplicate_flow(self, f): - return self.load_flow(f.copy()) + new_flow = f.copy() + new_flow.marked = False + return self.load_flow(new_flow) def create_request(self, method, scheme, host, port, path): """ -- cgit v1.2.3 From d45d0ce22aef2ec5a2c6ebbf0c2e0f4a1fa83f28 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 16:15:24 -0500 Subject: Added functionality to write marked flows to file w (write) -> m (marked) --- libmproxy/console/__init__.py | 7 +++++++ libmproxy/console/flowlist.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index cbcba52f..20580a28 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -594,6 +594,13 @@ class ConsoleMaster(flow.FlowMaster): def save_flows(self, path): return self._write_flows(path, self.state.view) + + def save_marked_flows(self, path): + marked_flows = [] + for f in self.state.view: + if f.marked: + marked_flows.append(f) + return self._write_flows(path, marked_flows) def load_flows_callback(self, path): if not path: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index f7835419..cd0b869b 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -121,6 +121,11 @@ class ConnectionItem(urwid.WidgetWrap): prompt = "Save all flows to", callback = self.master.save_flows ) + if k == "m": + signals.status_prompt_path.send( + prompt = "Save marked flows to", + callback = self.master.save_marked_flows + ) else: signals.status_prompt_path.send( prompt = "Save this flow to", @@ -220,6 +225,7 @@ class ConnectionItem(urwid.WidgetWrap): keys = ( ("all flows", "a"), ("this flow", "t"), + ("marked flows", "m"), ), callback = self.save_flows_prompt, ) -- cgit v1.2.3 From 486177edc7090539e063ec2a0dd70caffd8ec3cc Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 16:15:24 -0500 Subject: Added functionality to write marked flows to file w (write) -> m (marked) --- libmproxy/console/__init__.py | 7 +++++++ libmproxy/console/flowlist.py | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index cbcba52f..20580a28 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -594,6 +594,13 @@ class ConsoleMaster(flow.FlowMaster): def save_flows(self, path): return self._write_flows(path, self.state.view) + + def save_marked_flows(self, path): + marked_flows = [] + for f in self.state.view: + if f.marked: + marked_flows.append(f) + return self._write_flows(path, marked_flows) def load_flows_callback(self, path): if not path: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index f7835419..72d507c8 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -121,6 +121,11 @@ class ConnectionItem(urwid.WidgetWrap): prompt = "Save all flows to", callback = self.master.save_flows ) + elif k == "m": + signals.status_prompt_path.send( + prompt = "Save marked flows to", + callback = self.master.save_marked_flows + ) else: signals.status_prompt_path.send( prompt = "Save this flow to", @@ -220,6 +225,7 @@ class ConnectionItem(urwid.WidgetWrap): keys = ( ("all flows", "a"), ("this flow", "t"), + ("marked flows", "m"), ), callback = self.save_flows_prompt, ) -- cgit v1.2.3 From dd1e401e014be7b3251d08313ac6553282401cfe Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 16:32:13 -0500 Subject: Changed mark symbol Smaller symbol now, still just as easy to see while scrolling --- libmproxy/console/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 51911746..cbf39e6e 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -115,11 +115,11 @@ def fcol(s, attr): if urwid.util.detected_encoding: SYMBOL_REPLAY = u"\u21ba" SYMBOL_RETURN = u"\u2190" - SYMBOL_MARK = u"[M] \u2192" + SYMBOL_MARK = u"\u25cf" else: SYMBOL_REPLAY = u"[r]" SYMBOL_RETURN = u"<-" - SYMBOL_MARK = "[M] ==>" + SYMBOL_MARK = "[m]" def raw_format_flow(f, focus, extended, padding): -- cgit v1.2.3 From 2a6698bf5a2ebe576ae0bbcacdee69d6eed10be9 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 20:27:33 -0500 Subject: Moved marking from flow to console No longer taints the flow primitive --- libmproxy/console/__init__.py | 20 +++++++++++++++++++- libmproxy/console/common.py | 5 +++-- libmproxy/console/flowlist.py | 8 ++++++-- libmproxy/flow.py | 15 +-------------- libmproxy/protocol/primitives.py | 7 ------- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 20580a28..3d20947b 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -48,6 +48,7 @@ class ConsoleState(flow.State): self.set_focus(0) elif self.follow_focus: self.set_focus(len(self.view) - 1) + self.set_flow_marked(f, False) return f def update_flow(self, f): @@ -100,12 +101,29 @@ class ConsoleState(flow.State): return ret def clear(self): + marked_flows = [] + for f in self.flows: + if self.flow_marked(f): + marked_flows.append(f) + super(ConsoleState, self).clear() + + for f in marked_flows: + self.add_flow(f) + self.set_flow_marked(f, True) + if len(self.flows.views) == 0: self.focus = None else: self.focus = 0 self.set_focus(self.focus) + + def flow_marked(self, flow): + return self.get_flow_setting(flow, "marked", False) + + def set_flow_marked(self, flow, marked): + self.add_flow_setting(flow, "marked", marked) + class Options(object): attributes = [ @@ -598,7 +616,7 @@ class ConsoleMaster(flow.FlowMaster): def save_marked_flows(self, path): marked_flows = [] for f in self.state.view: - if f.marked: + if self.state.flow_marked(f): marked_flows.append(f) return self._write_flows(path, marked_flows) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index cbf39e6e..90bccfe7 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -378,7 +378,8 @@ def ask_save_body(part, master, state, flow): flowcache = utils.LRUCache(800) -def format_flow(f, focus, extended=False, hostheader=False, padding=2): +def format_flow(f, focus, extended=False, hostheader=False, padding=2, + marked=False): d = dict( intercepted = f.intercepted, acked = f.reply.acked, @@ -391,7 +392,7 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2): err_msg = f.error.msg if f.error else None, resp_code = f.response.code if f.response else None, - marked = f.marked, + marked = marked, ) if f.response: if f.response.content: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 72d507c8..87e7c77a 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -109,7 +109,8 @@ class ConnectionItem(urwid.WidgetWrap): return common.format_flow( self.flow, self.f, - hostheader = self.master.showhost + hostheader = self.master.showhost, + marked=self.state.flow_marked(self.flow) ) def selectable(self): @@ -184,7 +185,10 @@ class ConnectionItem(urwid.WidgetWrap): f = self.master.duplicate_flow(self.flow) self.master.view_flow(f) elif key == "m": - self.flow.toggle_mark() + if self.state.flow_marked(self.flow): + self.state.set_flow_marked(self.flow, False) + else: + self.state.set_flow_marked(self.flow, True) signals.flowlist_change.send(self) elif key == "r": r = self.master.replay_request(self.flow) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 0dffc8d3..1a052f51 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -494,19 +494,8 @@ class FlowStore(FlowList): self._recalculate_views() def _clear(self): - marked_flows = [] - for f in self._list: - if f.marked: - marked_flows.append(f) - if len(marked_flows) == len(self._list): - marked_flows = [] - self._list = [] self._set = set() - - for f in marked_flows: - self._add(f) - self._recalculate_views() def _recalculate_views(self): @@ -815,9 +804,7 @@ class FlowMaster(controller.Master): return super(FlowMaster, self).tick(q, timeout) def duplicate_flow(self, f): - new_flow = f.copy() - new_flow.marked = False - return self.load_flow(new_flow) + return self.load_flow(f.copy()) def create_request(self, method, scheme, host, port, path): """ diff --git a/libmproxy/protocol/primitives.py b/libmproxy/protocol/primitives.py index 1d2389c3..2f8ea3e0 100644 --- a/libmproxy/protocol/primitives.py +++ b/libmproxy/protocol/primitives.py @@ -77,7 +77,6 @@ class Flow(stateobject.StateObject): """@type: bool""" self._backup = None self.reply = None - self.marked = False _stateobject_attributes = dict( id=str, @@ -166,12 +165,6 @@ class Flow(stateobject.StateObject): self.intercepted = False self.reply() master.handle_accept_intercept(self) - - def toggle_mark(self): - if self.marked: - self.marked = False - else: - self.marked = True class ProtocolHandler(object): -- cgit v1.2.3 From 946030367fee0d624a29ba57a11d5f2d1dea4105 Mon Sep 17 00:00:00 2001 From: Jake Drahos Date: Thu, 11 Jun 2015 20:31:54 -0500 Subject: Added unmark all functionality - 'U' to unmark all marked flows --- libmproxy/console/flowlist.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 87e7c77a..bb23df75 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -21,6 +21,7 @@ def _mkhelp(): ("n", "create a new request"), ("P", "copy flow to clipboard"), ("r", "replay request"), + ("U", "unmark all marked flows"), ("V", "revert changes to request"), ("w", "save flows "), ("W", "stream flows to file"), @@ -215,6 +216,10 @@ class ConnectionItem(urwid.WidgetWrap): ), callback = self.stop_server_playback_prompt, ) + elif key == "U": + for f in self.state.flows: + self.state.set_flow_marked(f, False) + signals.flowlist_change.send(self) elif key == "V": if not self.flow.modified(): signals.status_message.send(message="Flow not modified.") -- cgit v1.2.3