diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 1b65ae686..198b7bbee 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -765,7 +765,7 @@ class ConsoleMaster(flow.FlowMaster): def run(self): self.ui = urwid.raw_display.Screen() self.ui.set_terminal_properties(256) - self.ui.register_palette(self.palette) + self.ui.register_palette(self.palette.palette()) self.flow_list_walker = flowlist.FlowListWalker(self, self.state) self.view = None self.statusbar = None diff --git a/libmproxy/console/flowdetailview.py b/libmproxy/console/flowdetailview.py index 4164c4167..f351bff10 100644 --- a/libmproxy/console/flowdetailview.py +++ b/libmproxy/console/flowdetailview.py @@ -21,7 +21,7 @@ class FlowDetailsView(urwid.ListBox): self.master.statusbar = self.state[0] self.master.body = self.state[1] self.master.header = self.state[2] - self.master.make_view() + self.master.loop.widget = self.master.make_view() return None elif key == "?": key = None diff --git a/libmproxy/console/help.py b/libmproxy/console/help.py index fddab5378..6bb49a921 100644 --- a/libmproxy/console/help.py +++ b/libmproxy/console/help.py @@ -183,7 +183,7 @@ class HelpView(urwid.ListBox): self.master.statusbar = self.state[0] self.master.body = self.state[1] self.master.header = self.state[2] - self.master.make_view() + self.master.loop.widget = self.master.make_view() return None elif key == "?": key = None diff --git a/libmproxy/console/palettes.py b/libmproxy/console/palettes.py index 650cf2618..cfb2702c4 100644 --- a/libmproxy/console/palettes.py +++ b/libmproxy/console/palettes.py @@ -1,192 +1,261 @@ + +# Low-color themes should ONLY use the standard foreground and background +# colours listed here: +# +# http://urwid.org/manual/displayattributes.html +# + + + +class Palette: + _fields = [ + 'title', + + # Status bar & heading + 'heading', 'heading_key', 'heading_inactive', + + # Help + 'key', 'head', 'text', + + # List and Connections + 'method', 'focus', + 'code_200', 'code_300', 'code_400', 'code_500', 'code_other', + 'error', + 'header', 'highlight', 'intercept', 'replay', + + # Hex view + 'offset', + + # Grid Editor + 'focusfield', 'focusfield_error', 'field_error', 'editfield', + ] + high = None + + def palette(self): + l = [] + for i in self._fields: + v = [i] + v.extend(self.low[i]) + if self.high and i in self.high: + v.append(None) + v.extend(self.high[i]) + l.append(tuple(v)) + return l + + +class LowDark(Palette): + """ + Low-color dark background + """ + low = dict( + title = ('white,bold', 'default'), + + # Status bar & heading + heading = ('light gray', 'dark blue'), + heading_key = ('light cyan', 'dark blue'), + heading_inactive = ('white', 'dark gray'), + + # Help + key = ('light cyan', 'default'), + head = ('white,bold', 'default'), + text = ('light gray', 'default'), + + # List and Connections + method = ('dark cyan', 'default'), + focus = ('yellow', 'default'), + + code_200 = ('dark green', 'default'), + code_300 = ('light blue', 'default'), + code_400 = ('light red', 'default'), + code_500 = ('light red', 'default'), + code_other = ('dark red', 'default'), + + error = ('light red', 'default'), + + header = ('dark cyan', 'default'), + highlight = ('white,bold', 'default'), + intercept = ('brown', 'default'), + replay = ('light green', 'default'), + + # Hex view + offset = ('dark cyan', 'default'), + + # Grid Editor + focusfield = ('black', 'light gray'), + focusfield_error = ('dark red', 'light gray'), + field_error = ('dark red', 'default'), + editfield = ('white', 'default'), + ) + + +class Dark(LowDark): + high = dict( + heading_inactive = ('g58', 'g11'), + intercept = ('#f60', 'default'), + ) + + +class LowLight(Palette): + """ + Low-color light background + """ + low = dict( + title = ('dark magenta,bold', 'light blue'), + + # Status bar & heading + heading = ('light gray', 'dark blue'), + heading_key = ('light cyan', 'dark blue'), + heading_inactive = ('black', 'light gray'), + + # Help + key = ('dark blue,bold', 'default'), + head = ('black,bold', 'default'), + text = ('dark gray', 'default'), + + # List and Connections + method = ('dark cyan', 'default'), + focus = ('black', 'default'), + + code_200 = ('dark green', 'default'), + code_300 = ('light blue', 'default'), + code_400 = ('dark red', 'default'), + code_500 = ('dark red', 'default'), + code_other = ('light red', 'default'), + + error = ('light red', 'default'), + + header = ('dark blue', 'default'), + highlight = ('black,bold', 'default'), + intercept = ('brown', 'default'), + replay = ('dark green', 'default'), + + # Hex view + offset = ('dark blue', 'default'), + + # Grid Editor + focusfield = ('black', 'light gray'), + focusfield_error = ('dark red', 'light gray'), + field_error = ('dark red', 'black'), + editfield = ('black', 'default'), + ) + + +class Light(LowLight): + high = dict( + heading = ('g99', '#08f'), + heading_key = ('#0ff,bold', '#08f'), + heading_inactive = ('g35', 'g85'), + replay = ('#0a0,bold', 'default'), + ) + + +# Solarized palette in Urwid-style terminal high-colour offsets +# See: http://ethanschoonover.com/solarized +sol_base03 = "h234" +sol_base02 = "h235" +sol_base01 = "h240" +sol_base00 = "h241" +sol_base0 = "h244" +sol_base1 = "h245" +sol_base2 = "h254" +sol_base3 = "h230" +sol_yellow = "h136" +sol_orange = "h166" +sol_red = "h160" +sol_magenta = "h125" +sol_violet = "h61" +sol_blue = "h33" +sol_cyan = "h37" +sol_green = "h64" +class SolarizedLight(LowLight): + high = dict( + title = (sol_blue, 'default'), + text = (sol_base00, 'default'), + + # Status bar & heading + heading = (sol_base2, sol_base02), + heading_key = (sol_blue, sol_base03), + heading_inactive = (sol_base03, sol_base1), + + # Help + key = (sol_blue, 'default',), + head = (sol_base00, 'default'), + + # List and Connections + method = (sol_cyan, 'default'), + focus = (sol_base01, 'default'), + + code_200 = (sol_green, 'default'), + code_300 = (sol_blue, 'default'), + code_400 = (sol_orange, 'default',), + code_500 = (sol_red, 'default'), + code_other = (sol_magenta, 'default'), + + error = (sol_red, 'default'), + + header = (sol_base01, 'default'), + highlight = (sol_base01, 'default'), + intercept = (sol_red, 'default',), + replay = (sol_green, 'default',), + + # Hex view + offset = (sol_cyan, 'default'), + + # Grid Editor + focusfield = (sol_base00, sol_base2), + focusfield_error = (sol_red, sol_base2), + field_error = (sol_red, 'default'), + editfield = (sol_base01, 'default'), + ) + + +class SolarizedDark(LowDark): + high = dict( + title = (sol_blue, 'default'), + text = (sol_base0, 'default'), + + # Status bar & heading + heading = (sol_base03, sol_base1), + heading_key = (sol_blue+",bold", sol_base1), + heading_inactive = (sol_base1, sol_base02), + + # Help + key = (sol_blue, 'default',), + head = (sol_base00, 'default'), + + # List and Connections + method = (sol_cyan, 'default'), + focus = (sol_base1, 'default'), + + code_200 = (sol_green, 'default'), + code_300 = (sol_blue, 'default'), + code_400 = (sol_orange, 'default',), + code_500 = (sol_red, 'default'), + code_other = (sol_magenta, 'default'), + + error = (sol_red, 'default'), + + header = (sol_base01, 'default'), + highlight = (sol_base01, 'default'), + intercept = (sol_red, 'default',), + replay = (sol_green, 'default',), + + # Hex view + offset = (sol_cyan, 'default'), + + # Grid Editor + focusfield = (sol_base0, sol_base02), + focusfield_error = (sol_red, sol_base02), + field_error = (sol_red, 'default'), + editfield = (sol_base1, 'default'), + ) + + palettes = { - -# Default palette for dark background - 'dark': [ - # name, foreground, background, mono, foreground_high, background_high - # For details on the meaning of the elements refer to - # http://excess.org/urwid/reference.html#Screen-register_palette - - ('body', 'black', 'dark cyan'), - ('foot', 'light gray', 'default'), - ('title', 'white,bold', 'default',), - ('editline', 'white', 'default',), - - # Status bar & heading - ('heading', 'light gray', 'dark blue', None, 'g85', 'dark blue'), - ('heading_key', 'light cyan', 'dark blue', None, 'light cyan', 'dark blue'), - ('heading_inactive', 'white', 'dark gray', None, 'g58', 'g11'), - - # Help - ('key', 'light cyan', 'default'), - ('head', 'white,bold', 'default'), - ('text', 'light gray', 'default'), - - # List and Connections - ('method', 'dark cyan', 'default'), - ('focus', 'yellow', 'default'), - - ('code_200', 'light green', 'default'), - ('code_300', 'light blue', 'default'), - ('code_400', 'light red', 'default', None, '#f60', 'default'), - ('code_500', 'light red', 'default'), - ('code_other', 'dark red', 'default'), - - ('error', 'light red', 'default'), - - ('header', 'dark cyan', 'default'), - ('highlight', 'white,bold', 'default'), - ('intercept', 'brown', 'default', None, '#f60', 'default'), - ('replay', 'light green', 'default', None, '#0f0', 'default'), - ('ack', 'light red', 'default'), - - # Hex view - ('offset', 'dark cyan', 'default'), - - # Grid Editor - ('focusfield', 'black', 'light gray'), - ('focusfield_error', 'dark red', 'light gray'), - ('field_error', 'dark red', 'black'), - ('editfield', 'black', 'light cyan'), - ], - -# Palette for light background - 'light': [ - ('body', 'black', 'dark cyan'), - ('foot', 'dark gray', 'default'), - ('title', 'white,bold', 'light blue',), - ('editline', 'white', 'default',), - - # Status bar & heading - ('heading', 'white', 'light gray', None, 'g85', 'dark blue'), - ('heading_key', 'dark blue', 'light gray', None, 'light cyan', 'dark blue'), - ('heading_inactive', 'light gray', 'dark gray', None, 'dark gray', 'dark blue'), - - # Help - ('key', 'dark blue,bold', 'default'), - ('head', 'black,bold', 'default'), - ('text', 'dark gray', 'default'), - - # List and Connections - ('method', 'dark cyan', 'default'), - ('focus', 'black', 'default'), - - ('code_200', 'dark green', 'default'), - ('code_300', 'light blue', 'default'), - ('code_400', 'dark red', 'default', None, '#f60', 'default'), - ('code_500', 'dark red', 'default'), - ('code_other', 'light red', 'default'), - - ('error', 'light red', 'default'), - - ('header', 'dark blue', 'default'), - ('highlight', 'black,bold', 'default'), - ('intercept', 'brown', 'default', None, '#f60', 'default'), - ('replay', 'dark green', 'default', None, '#0f0', 'default'), - ('ack', 'dark red', 'default'), - - # Hex view - ('offset', 'dark blue', 'default'), - - # Grid Editor - ('focusfield', 'black', 'light gray'), - ('focusfield_error', 'dark red', 'light gray'), - ('field_error', 'dark red', 'black'), - ('editfield', 'black', 'light cyan'), - ], - -# Palettes for terminals that use the Solarized precision colors -# (http://ethanschoonover.com/solarized#the-values) - -# For dark backgrounds - 'solarized_dark': [ - ('body', 'dark cyan', 'default'), - ('foot', 'dark gray', 'default'), - ('title', 'white,bold', 'default',), - ('editline', 'white', 'default',), - - # Status bar & heading - ('heading', 'light gray', 'light cyan',), - ('heading_key', 'dark blue', 'white',), - ('heading_inactive', 'light cyan', 'light gray',), - - # Help - ('key', 'dark blue', 'default',), - ('head', 'white,underline', 'default'), - ('text', 'light cyan', 'default'), - - # List and Connections - ('method', 'dark cyan', 'default'), - ('focus', 'white', 'default'), - - ('code_200', 'dark green', 'default'), - ('code_300', 'light blue', 'default'), - ('code_400', 'dark red', 'default',), - ('code_500', 'dark red', 'default'), - ('code_other', 'light red', 'default'), - - ('error', 'light red', 'default'), - - ('header', 'yellow', 'default'), - ('highlight', 'white', 'default'), - ('intercept', 'brown', 'default',), - ('replay', 'dark green', 'default',), - ('ack', 'dark red', 'default'), - - # Hex view - ('offset', 'yellow', 'default'), - ('text', 'light cyan', 'default'), - - # Grid Editor - ('focusfield', 'white', 'light cyan'), - ('focusfield_error', 'dark red', 'light gray'), - ('field_error', 'dark red', 'black'), - ('editfield', 'black', 'light gray'), - ], - -# For light backgrounds - 'solarized_light': [ - ('body', 'dark cyan', 'default'), - ('foot', 'dark gray', 'default'), - ('title', 'white,bold', 'light cyan',), - ('editline', 'white', 'default',), - - # Status bar & heading - ('heading', 'light cyan', 'light gray',), - ('heading_key', 'dark blue', 'white',), - ('heading_inactive', 'white', 'light gray',), - - # Help - ('key', 'dark blue', 'default',), - ('head', 'black,underline', 'default'), - ('text', 'light cyan', 'default'), - - # List and Connections - ('method', 'dark cyan', 'default'), - ('focus', 'black', 'default'), - - ('code_200', 'dark green', 'default'), - ('code_300', 'light blue', 'default'), - ('code_400', 'dark red', 'default',), - ('code_500', 'dark red', 'default'), - ('code_other', 'light red', 'default'), - - ('error', 'light red', 'default'), - - ('header', 'light cyan', 'default'), - ('highlight', 'black,bold', 'default'), - ('intercept', 'brown', 'default',), - ('replay', 'dark green', 'default',), - ('ack', 'dark red', 'default'), - - # Hex view - ('offset', 'light cyan', 'default'), - ('text', 'yellow', 'default'), - - # Grid Editor - ('focusfield', 'black', 'light gray'), - ('focusfield_error', 'dark red', 'light gray'), - ('field_error', 'dark red', 'black'), - ('editfield', 'white', 'light cyan'), - ], - + "lowlight": LowLight(), + "lowdark": LowDark(), + "light": Light(), + "dark": Dark(), + "solarized_light": SolarizedLight(), + "solarized_dark": SolarizedDark(), } diff --git a/test/test_console_help.py b/test/test_console_help.py index 6e1f9fadc..a410bd2e5 100644 --- a/test/test_console_help.py +++ b/test/test_console_help.py @@ -5,7 +5,14 @@ if os.name == "nt": import libmproxy.console.help as help +class DummyLoop: + def __init__(self): + self.widget = None + class DummyMaster: + def __init__(self): + self.loop = DummyLoop() + def make_view(self): pass @@ -16,7 +23,8 @@ class TestHelp: assert h.helptext() def test_keypress(self): - h = help.HelpView(DummyMaster(), "foo", [1, 2, 3]) + master = DummyMaster() + h = help.HelpView(master, "foo", [1, 2, 3]) assert not h.keypress((0, 0), "q") assert not h.keypress((0, 0), "?") assert h.keypress((0, 0), "o") == "o" diff --git a/test/test_console_palettes.py b/test/test_console_palettes.py new file mode 100644 index 000000000..3f8e280a4 --- /dev/null +++ b/test/test_console_palettes.py @@ -0,0 +1,11 @@ +import os +from nose.plugins.skip import SkipTest +if os.name == "nt": + raise SkipTest("Skipped on Windows.") +import libmproxy.console.palettes as palettes + + +class TestPalette: + def test_helptext(self): + for i in palettes.palettes.values(): + assert i.palette() diff --git a/test/test_dump.py b/test/test_dump.py index 11a024e38..48eeb244a 100644 --- a/test/test_dump.py +++ b/test/test_dump.py @@ -131,14 +131,16 @@ class TestDumpMaster: assert len(m.apps.apps) == 1 def test_replacements(self): + cs = StringIO() o = dump.Options(replacements=[(".*", "content", "foo")]) - m = dump.DumpMaster(None, o) + m = dump.DumpMaster(None, o, outfile=cs) f = self._cycle(m, "content") assert f.request.content == "foo" def test_setheader(self): + cs = StringIO() o = dump.Options(setheaders=[(".*", "one", "two")]) - m = dump.DumpMaster(None, o) + m = dump.DumpMaster(None, o, outfile=cs) f = self._cycle(m, "content") assert f.request.headers["one"] == ["two"] @@ -195,4 +197,3 @@ class TestDumpMaster: def test_stickyauth(self): self._dummy_cycle(1, None, "", stickyauth = ".*") - diff --git a/test/tools/testpatt b/test/tools/testpatt new file mode 100755 index 000000000..f6d1169b2 --- /dev/null +++ b/test/tools/testpatt @@ -0,0 +1,9 @@ +#!/bin/bash + +# Generate a test pattern with pathoc +PATHOD=http://localhost:9999 +pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@200b'" +pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@200b'" +pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@200b'" +pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@200b'" +pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@200b'"