mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-27 02:24:18 +00:00
console: first pass of a Set-cookie editor for responses
This commit is contained in:
parent
850a50262b
commit
52716e3439
@ -66,20 +66,26 @@ def format_keyvals(lst, key="key", val="text", indent=0):
|
|||||||
if kv is None:
|
if kv is None:
|
||||||
ret.append(urwid.Text(""))
|
ret.append(urwid.Text(""))
|
||||||
else:
|
else:
|
||||||
cols = []
|
if isinstance(kv[1], urwid.Widget):
|
||||||
# This cumbersome construction process is here for a reason:
|
v = kv[1]
|
||||||
# Urwid < 1.0 barfs if given a fixed size column of size zero.
|
elif kv[1] is None:
|
||||||
if indent:
|
v = urwid.Text("")
|
||||||
cols.append(("fixed", indent, urwid.Text("")))
|
else:
|
||||||
cols.extend([
|
v = urwid.Text([(val, kv[1])])
|
||||||
(
|
ret.append(
|
||||||
"fixed",
|
urwid.Columns(
|
||||||
maxk,
|
[
|
||||||
urwid.Text([(key, kv[0] or "")])
|
("fixed", indent, urwid.Text("")),
|
||||||
),
|
(
|
||||||
kv[1] if isinstance(kv[1], urwid.Widget) else urwid.Text([(val, kv[1])])
|
"fixed",
|
||||||
])
|
maxk,
|
||||||
ret.append(urwid.Columns(cols, dividechars = 2))
|
urwid.Text([(key, kv[0] or "")])
|
||||||
|
),
|
||||||
|
v
|
||||||
|
],
|
||||||
|
dividechars = 2
|
||||||
|
)
|
||||||
|
)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@ -316,6 +316,19 @@ class FlowView(tabs.Tabs):
|
|||||||
conn.set_cookies(od)
|
conn.set_cookies(od)
|
||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
|
|
||||||
|
def set_setcookies(self, lst, conn):
|
||||||
|
vals = []
|
||||||
|
for i in lst:
|
||||||
|
vals.append(
|
||||||
|
[
|
||||||
|
i[0],
|
||||||
|
[i[1], odict.ODictCaseless(i[2])]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
od = odict.ODict(vals)
|
||||||
|
conn.set_cookies(od)
|
||||||
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
|
|
||||||
def edit(self, part):
|
def edit(self, part):
|
||||||
if self.tab_offset == TAB_REQ:
|
if self.tab_offset == TAB_REQ:
|
||||||
message = self.flow.request
|
message = self.flow.request
|
||||||
@ -338,7 +351,18 @@ class FlowView(tabs.Tabs):
|
|||||||
message
|
message
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
pass
|
if message == self.flow.response and part == "c":
|
||||||
|
flattened = []
|
||||||
|
for k, v in message.get_cookies().items():
|
||||||
|
flattened.append([k, v[0], v[1].lst])
|
||||||
|
self.master.view_grideditor(
|
||||||
|
grideditor.SetCookieEditor(
|
||||||
|
self.master,
|
||||||
|
flattened,
|
||||||
|
self.set_setcookies,
|
||||||
|
message
|
||||||
|
)
|
||||||
|
)
|
||||||
if part == "r":
|
if part == "r":
|
||||||
with decoded(message):
|
with decoded(message):
|
||||||
# Fix an issue caused by some editors when editing a
|
# Fix an issue caused by some editors when editing a
|
||||||
@ -541,7 +565,7 @@ class FlowView(tabs.Tabs):
|
|||||||
signals.status_prompt_onekey.send(
|
signals.status_prompt_onekey.send(
|
||||||
prompt = "Edit request",
|
prompt = "Edit request",
|
||||||
keys = (
|
keys = (
|
||||||
("cookie", "c"),
|
("cookies", "c"),
|
||||||
("query", "q"),
|
("query", "q"),
|
||||||
("path", "p"),
|
("path", "p"),
|
||||||
("url", "u"),
|
("url", "u"),
|
||||||
@ -556,6 +580,7 @@ class FlowView(tabs.Tabs):
|
|||||||
signals.status_prompt_onekey.send(
|
signals.status_prompt_onekey.send(
|
||||||
prompt = "Edit response",
|
prompt = "Edit response",
|
||||||
keys = (
|
keys = (
|
||||||
|
("cookies", "c"),
|
||||||
("code", "o"),
|
("code", "o"),
|
||||||
("message", "m"),
|
("message", "m"),
|
||||||
("header", "h"),
|
("header", "h"),
|
||||||
|
@ -7,7 +7,7 @@ import urwid
|
|||||||
|
|
||||||
from . import common, signals
|
from . import common, signals
|
||||||
from .. import utils, filt, script
|
from .. import utils, filt, script
|
||||||
from netlib import http_uastrings
|
from netlib import http_uastrings, http_cookies
|
||||||
|
|
||||||
|
|
||||||
FOOTER = [
|
FOOTER = [
|
||||||
@ -19,17 +19,36 @@ FOOTER_EDITING = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SText(urwid.WidgetWrap):
|
class TextColumn:
|
||||||
def __init__(self, txt, focused, error):
|
subeditor = None
|
||||||
|
|
||||||
|
def __init__(self, heading):
|
||||||
|
self.heading = heading
|
||||||
|
|
||||||
|
def text(self, obj):
|
||||||
|
return SEscaped(obj or "")
|
||||||
|
|
||||||
|
def blank(self):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class SubgridColumn:
|
||||||
|
def __init__(self, heading, subeditor):
|
||||||
|
self.heading = heading
|
||||||
|
self.subeditor = subeditor
|
||||||
|
|
||||||
|
def text(self, obj):
|
||||||
|
p = http_cookies._format_pairs(obj, sep="\n")
|
||||||
|
return urwid.Text(p)
|
||||||
|
|
||||||
|
def blank(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class SEscaped(urwid.WidgetWrap):
|
||||||
|
def __init__(self, txt):
|
||||||
txt = txt.encode("string-escape")
|
txt = txt.encode("string-escape")
|
||||||
w = urwid.Text(txt, wrap="any")
|
w = urwid.Text(txt, wrap="any")
|
||||||
if focused:
|
|
||||||
if error:
|
|
||||||
w = urwid.AttrWrap(w, "focusfield_error")
|
|
||||||
else:
|
|
||||||
w = urwid.AttrWrap(w, "focusfield")
|
|
||||||
elif error:
|
|
||||||
w = urwid.AttrWrap(w, "field_error")
|
|
||||||
urwid.WidgetWrap.__init__(self, w)
|
urwid.WidgetWrap.__init__(self, w)
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
@ -50,7 +69,7 @@ class SEdit(urwid.WidgetWrap):
|
|||||||
urwid.WidgetWrap.__init__(self, w)
|
urwid.WidgetWrap.__init__(self, w)
|
||||||
|
|
||||||
def get_text(self):
|
def get_text(self):
|
||||||
return self._w.get_text()[0]
|
return self._w.get_text()[0].strip()
|
||||||
|
|
||||||
def selectable(self):
|
def selectable(self):
|
||||||
return True
|
return True
|
||||||
@ -67,9 +86,15 @@ class GridRow(urwid.WidgetWrap):
|
|||||||
self.editing = SEdit(v)
|
self.editing = SEdit(v)
|
||||||
self.fields.append(self.editing)
|
self.fields.append(self.editing)
|
||||||
else:
|
else:
|
||||||
self.fields.append(
|
w = self.editor.columns[i].text(v)
|
||||||
SText(v, True if focused == i else False, i in errors)
|
if focused == i:
|
||||||
)
|
if i in errors:
|
||||||
|
w = urwid.AttrWrap(w, "focusfield_error")
|
||||||
|
else:
|
||||||
|
w = urwid.AttrWrap(w, "focusfield")
|
||||||
|
elif i in errors:
|
||||||
|
w = urwid.AttrWrap(w, "field_error")
|
||||||
|
self.fields.append(w)
|
||||||
|
|
||||||
fspecs = self.fields[:]
|
fspecs = self.fields[:]
|
||||||
if len(self.fields) > 1:
|
if len(self.fields) > 1:
|
||||||
@ -126,7 +151,9 @@ class GridWalker(urwid.ListWalker):
|
|||||||
val = val.decode("string-escape")
|
val = val.decode("string-escape")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
signals.status_message.send(
|
signals.status_message.send(
|
||||||
self, message = "Invalid Python-style string encoding.", expure = 1000
|
self,
|
||||||
|
message = "Invalid Python-style string encoding.",
|
||||||
|
expire = 1000
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
errors = self.lst[self.focus][1]
|
errors = self.lst[self.focus][1]
|
||||||
@ -136,10 +163,15 @@ class GridWalker(urwid.ListWalker):
|
|||||||
errors.add(self.focus_col)
|
errors.add(self.focus_col)
|
||||||
else:
|
else:
|
||||||
errors.discard(self.focus_col)
|
errors.discard(self.focus_col)
|
||||||
|
self.set_value(val, self.focus, self.focus_col, errors)
|
||||||
|
|
||||||
row = list(self.lst[self.focus][0])
|
def set_value(self, val, focus, focus_col, errors=None):
|
||||||
row[self.focus_col] = val
|
if not errors:
|
||||||
self.lst[self.focus] = [tuple(row), errors]
|
errors = set([])
|
||||||
|
row = list(self.lst[focus][0])
|
||||||
|
row[focus_col] = val
|
||||||
|
self.lst[focus] = [tuple(row), errors]
|
||||||
|
self._modified()
|
||||||
|
|
||||||
def delete_focus(self):
|
def delete_focus(self):
|
||||||
if self.lst:
|
if self.lst:
|
||||||
@ -149,7 +181,10 @@ class GridWalker(urwid.ListWalker):
|
|||||||
|
|
||||||
def _insert(self, pos):
|
def _insert(self, pos):
|
||||||
self.focus = pos
|
self.focus = pos
|
||||||
self.lst.insert(self.focus, [[""]*self.editor.columns, set([])])
|
self.lst.insert(
|
||||||
|
self.focus, [
|
||||||
|
[c.blank() for c in self.editor.columns], set([])]
|
||||||
|
)
|
||||||
self.focus_col = 0
|
self.focus_col = 0
|
||||||
self.start_edit()
|
self.start_edit()
|
||||||
|
|
||||||
@ -179,12 +214,12 @@ class GridWalker(urwid.ListWalker):
|
|||||||
self._modified()
|
self._modified()
|
||||||
|
|
||||||
def right(self):
|
def right(self):
|
||||||
self.focus_col = min(self.focus_col + 1, self.editor.columns-1)
|
self.focus_col = min(self.focus_col + 1, len(self.editor.columns)-1)
|
||||||
self._modified()
|
self._modified()
|
||||||
|
|
||||||
def tab_next(self):
|
def tab_next(self):
|
||||||
self.stop_edit()
|
self.stop_edit()
|
||||||
if self.focus_col < self.editor.columns-1:
|
if self.focus_col < len(self.editor.columns)-1:
|
||||||
self.focus_col += 1
|
self.focus_col += 1
|
||||||
elif self.focus != len(self.lst)-1:
|
elif self.focus != len(self.lst)-1:
|
||||||
self.focus_col = 0
|
self.focus_col = 0
|
||||||
@ -231,7 +266,6 @@ FIRST_WIDTH_MIN = 20
|
|||||||
class GridEditor(urwid.WidgetWrap):
|
class GridEditor(urwid.WidgetWrap):
|
||||||
title = None
|
title = None
|
||||||
columns = None
|
columns = None
|
||||||
headings = None
|
|
||||||
|
|
||||||
def __init__(self, master, value, callback, *cb_args, **cb_kwargs):
|
def __init__(self, master, value, callback, *cb_args, **cb_kwargs):
|
||||||
value = copy.deepcopy(value)
|
value = copy.deepcopy(value)
|
||||||
@ -241,7 +275,7 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
first_width = 20
|
first_width = 20
|
||||||
if value:
|
if value:
|
||||||
for r in value:
|
for r in value:
|
||||||
assert len(r) == self.columns
|
assert len(r) == len(self.columns)
|
||||||
first_width = max(len(r), first_width)
|
first_width = max(len(r), first_width)
|
||||||
self.first_width = min(first_width, FIRST_WIDTH_MAX)
|
self.first_width = min(first_width, FIRST_WIDTH_MAX)
|
||||||
|
|
||||||
@ -250,9 +284,9 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
title = urwid.AttrWrap(title, "heading")
|
title = urwid.AttrWrap(title, "heading")
|
||||||
|
|
||||||
headings = []
|
headings = []
|
||||||
for i, h in enumerate(self.headings):
|
for i, col in enumerate(self.columns):
|
||||||
c = urwid.Text(h)
|
c = urwid.Text(col.heading)
|
||||||
if i == 0 and len(self.headings) > 1:
|
if i == 0 and len(self.columns) > 1:
|
||||||
headings.append(("fixed", first_width + 2, c))
|
headings.append(("fixed", first_width + 2, c))
|
||||||
else:
|
else:
|
||||||
headings.append(c)
|
headings.append(c)
|
||||||
@ -303,6 +337,9 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
except IOError, v:
|
except IOError, v:
|
||||||
return str(v)
|
return str(v)
|
||||||
|
|
||||||
|
def set_subeditor_value(self, val, focus, focus_col):
|
||||||
|
self.walker.set_value(val, focus, focus_col)
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
if self.walker.editing:
|
if self.walker.editing:
|
||||||
if key in ["esc"]:
|
if key in ["esc"]:
|
||||||
@ -317,10 +354,11 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
key = common.shortcuts(key)
|
key = common.shortcuts(key)
|
||||||
|
column = self.columns[self.walker.focus_col]
|
||||||
if key in ["q", "esc"]:
|
if key in ["q", "esc"]:
|
||||||
res = []
|
res = []
|
||||||
for i in self.walker.lst:
|
for i in self.walker.lst:
|
||||||
if not i[1] and any([x.strip() for x in i[0]]):
|
if not i[1] and any([x for x in i[0]]):
|
||||||
res.append(i[0])
|
res.append(i[0])
|
||||||
self.callback(res, *self.cb_args, **self.cb_kwargs)
|
self.callback(res, *self.cb_args, **self.cb_kwargs)
|
||||||
signals.pop_view_state.send(self)
|
signals.pop_view_state.send(self)
|
||||||
@ -337,6 +375,13 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
elif key == "d":
|
elif key == "d":
|
||||||
self.walker.delete_focus()
|
self.walker.delete_focus()
|
||||||
elif key == "r":
|
elif key == "r":
|
||||||
|
if column.subeditor:
|
||||||
|
signals.status_message.send(
|
||||||
|
self,
|
||||||
|
message = "Press enter to edit this field.",
|
||||||
|
expire = 1000
|
||||||
|
)
|
||||||
|
return
|
||||||
if self.walker.get_current_value() is not None:
|
if self.walker.get_current_value() is not None:
|
||||||
signals.status_prompt_path.send(
|
signals.status_prompt_path.send(
|
||||||
self,
|
self,
|
||||||
@ -344,6 +389,13 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
callback = self.read_file
|
callback = self.read_file
|
||||||
)
|
)
|
||||||
elif key == "R":
|
elif key == "R":
|
||||||
|
if column.subeditor:
|
||||||
|
signals.status_message.send(
|
||||||
|
self,
|
||||||
|
message = "Press enter to edit this field.",
|
||||||
|
expire = 1000
|
||||||
|
)
|
||||||
|
return
|
||||||
if self.walker.get_current_value() is not None:
|
if self.walker.get_current_value() is not None:
|
||||||
signals.status_prompt_path.send(
|
signals.status_prompt_path.send(
|
||||||
self,
|
self,
|
||||||
@ -352,6 +404,13 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
args = (True,)
|
args = (True,)
|
||||||
)
|
)
|
||||||
elif key == "e":
|
elif key == "e":
|
||||||
|
if column.subeditor:
|
||||||
|
signals.status_message.send(
|
||||||
|
self,
|
||||||
|
message = "Press enter to edit this field.",
|
||||||
|
expire = 1000
|
||||||
|
)
|
||||||
|
return
|
||||||
o = self.walker.get_current_value()
|
o = self.walker.get_current_value()
|
||||||
if o is not None:
|
if o is not None:
|
||||||
n = self.master.spawn_editor(o.encode("string-escape"))
|
n = self.master.spawn_editor(o.encode("string-escape"))
|
||||||
@ -359,7 +418,19 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
self.walker.set_current_value(n, False)
|
self.walker.set_current_value(n, False)
|
||||||
self.walker._modified()
|
self.walker._modified()
|
||||||
elif key in ["enter"]:
|
elif key in ["enter"]:
|
||||||
self.walker.start_edit()
|
if column.subeditor:
|
||||||
|
self.master.view_grideditor(
|
||||||
|
self.columns[self.walker.focus_col].subeditor(
|
||||||
|
self.master,
|
||||||
|
self.walker.get_current_value(),
|
||||||
|
self.set_subeditor_value,
|
||||||
|
self.walker.focus,
|
||||||
|
self.walker.focus_col
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.walker.start_edit()
|
||||||
|
|
||||||
elif not self.handle_key(key):
|
elif not self.handle_key(key):
|
||||||
return self._w.keypress(size, key)
|
return self._w.keypress(size, key)
|
||||||
|
|
||||||
@ -403,14 +474,18 @@ class GridEditor(urwid.WidgetWrap):
|
|||||||
|
|
||||||
class QueryEditor(GridEditor):
|
class QueryEditor(GridEditor):
|
||||||
title = "Editing query"
|
title = "Editing query"
|
||||||
columns = 2
|
columns = [
|
||||||
headings = ("Key", "Value")
|
TextColumn("Key"),
|
||||||
|
TextColumn("Value")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class HeaderEditor(GridEditor):
|
class HeaderEditor(GridEditor):
|
||||||
title = "Editing headers"
|
title = "Editing headers"
|
||||||
columns = 2
|
columns = [
|
||||||
headings = ("Key", "Value")
|
TextColumn("Key"),
|
||||||
|
TextColumn("Value")
|
||||||
|
]
|
||||||
|
|
||||||
def make_help(self):
|
def make_help(self):
|
||||||
h = GridEditor.make_help(self)
|
h = GridEditor.make_help(self)
|
||||||
@ -448,14 +523,19 @@ class HeaderEditor(GridEditor):
|
|||||||
|
|
||||||
class URLEncodedFormEditor(GridEditor):
|
class URLEncodedFormEditor(GridEditor):
|
||||||
title = "Editing URL-encoded form"
|
title = "Editing URL-encoded form"
|
||||||
columns = 2
|
columns = [
|
||||||
headings = ("Key", "Value")
|
TextColumn("Key"),
|
||||||
|
TextColumn("Value")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ReplaceEditor(GridEditor):
|
class ReplaceEditor(GridEditor):
|
||||||
title = "Editing replacement patterns"
|
title = "Editing replacement patterns"
|
||||||
columns = 3
|
columns = [
|
||||||
headings = ("Filter", "Regex", "Replacement")
|
TextColumn("Filter"),
|
||||||
|
TextColumn("Regex"),
|
||||||
|
TextColumn("Replacement"),
|
||||||
|
]
|
||||||
|
|
||||||
def is_error(self, col, val):
|
def is_error(self, col, val):
|
||||||
if col == 0:
|
if col == 0:
|
||||||
@ -471,8 +551,11 @@ class ReplaceEditor(GridEditor):
|
|||||||
|
|
||||||
class SetHeadersEditor(GridEditor):
|
class SetHeadersEditor(GridEditor):
|
||||||
title = "Editing header set patterns"
|
title = "Editing header set patterns"
|
||||||
columns = 3
|
columns = [
|
||||||
headings = ("Filter", "Header", "Value")
|
TextColumn("Filter"),
|
||||||
|
TextColumn("Header"),
|
||||||
|
TextColumn("Value"),
|
||||||
|
]
|
||||||
|
|
||||||
def is_error(self, col, val):
|
def is_error(self, col, val):
|
||||||
if col == 0:
|
if col == 0:
|
||||||
@ -517,14 +600,16 @@ class SetHeadersEditor(GridEditor):
|
|||||||
|
|
||||||
class PathEditor(GridEditor):
|
class PathEditor(GridEditor):
|
||||||
title = "Editing URL path components"
|
title = "Editing URL path components"
|
||||||
columns = 1
|
columns = [
|
||||||
headings = ("Component",)
|
TextColumn("Component"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ScriptEditor(GridEditor):
|
class ScriptEditor(GridEditor):
|
||||||
title = "Editing scripts"
|
title = "Editing scripts"
|
||||||
columns = 1
|
columns = [
|
||||||
headings = ("Command",)
|
TextColumn("Command"),
|
||||||
|
]
|
||||||
|
|
||||||
def is_error(self, col, val):
|
def is_error(self, col, val):
|
||||||
try:
|
try:
|
||||||
@ -535,8 +620,9 @@ class ScriptEditor(GridEditor):
|
|||||||
|
|
||||||
class HostPatternEditor(GridEditor):
|
class HostPatternEditor(GridEditor):
|
||||||
title = "Editing host patterns"
|
title = "Editing host patterns"
|
||||||
columns = 1
|
columns = [
|
||||||
headings = ("Regex (matched on hostname:port / ip:port)",)
|
TextColumn("Regex (matched on hostname:port / ip:port)")
|
||||||
|
]
|
||||||
|
|
||||||
def is_error(self, col, val):
|
def is_error(self, col, val):
|
||||||
try:
|
try:
|
||||||
@ -547,11 +633,24 @@ class HostPatternEditor(GridEditor):
|
|||||||
|
|
||||||
class CookieEditor(GridEditor):
|
class CookieEditor(GridEditor):
|
||||||
title = "Editing request Cookie header"
|
title = "Editing request Cookie header"
|
||||||
columns = 2
|
columns = [
|
||||||
headings = ("Name", "Value")
|
TextColumn("Name"),
|
||||||
|
TextColumn("Value"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class CookieAttributeEditor(GridEditor):
|
||||||
|
title = "Editing Set-Cookie attributes"
|
||||||
|
columns = [
|
||||||
|
TextColumn("Name"),
|
||||||
|
TextColumn("Value"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class SetCookieEditor(GridEditor):
|
class SetCookieEditor(GridEditor):
|
||||||
title = "Editing request SetCookie header"
|
title = "Editing response SetCookie header"
|
||||||
columns = 2
|
columns = [
|
||||||
headings = ("Name", "Value")
|
TextColumn("Name"),
|
||||||
|
TextColumn("Value"),
|
||||||
|
SubgridColumn("Attributes", CookieAttributeEditor),
|
||||||
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user