async def handle_lifecycle(self, event: hooks.Hook): """ Handle a lifecycle event. """ message = event.args()[0] if not hasattr(message, "reply"): # pragma: no cover raise exceptions.ControlException( "Message %s has no reply attribute" % message) # We can use DummyReply objects multiple times. We only clear them up on # the next handler so that we can access value and state in the # meantime. if isinstance(message.reply, controller.DummyReply): message.reply.reset() self.trigger(event) if message.reply.state == "start": message.reply.take() message.reply.commit() if isinstance(message.reply, controller.DummyReply): message.reply.mark_reset() if isinstance(message, flow.Flow): self.trigger(hooks.UpdateHook([message]))
def mark_toggle(self, flows: typing.Sequence[flow.Flow]) -> None: """ Toggle mark for flows. """ for i in flows: i.marked = not i.marked ctx.master.addons.trigger(hooks.UpdateHook(flows))
def resume(self, flows: typing.Sequence[flow.Flow]) -> None: """ Resume flows if they are intercepted. """ intercepted = [i for i in flows if i.intercepted] for f in intercepted: f.resume() ctx.master.addons.trigger(hooks.UpdateHook(intercepted))
def flow_set( self, flows: typing.Sequence[flow.Flow], attr: str, value: str ) -> None: """ Quickly set a number of common values on flows. """ val: typing.Union[int, str] = value if attr == "status_code": try: val = int(val) # type: ignore except ValueError as v: raise exceptions.CommandError( "Status code is not an integer: %s" % val ) from v updated = [] for f in flows: req = getattr(f, "request", None) rupdate = True if req: if attr == "method": req.method = val elif attr == "host": req.host = val elif attr == "path": req.path = val elif attr == "url": try: req.url = val except ValueError as e: raise exceptions.CommandError( "URL {} is invalid: {}".format(repr(val), e) ) from e else: self.rupdate = False resp = getattr(f, "response", None) supdate = True if resp: if attr == "status_code": resp.status_code = val if val in status_codes.RESPONSES: resp.reason = status_codes.RESPONSES[val] # type: ignore elif attr == "reason": resp.reason = val else: supdate = False if rupdate or supdate: updated.append(f) ctx.master.addons.trigger(hooks.UpdateHook(updated)) ctx.log.alert("Set {} on {} flows.".format(attr, len(updated)))
def setvalue(self, flows: typing.Sequence[mitmproxy.flow.Flow], key: str, value: str) -> None: """ Set a value in the settings store for the specified flows. """ updated = [] for f in flows: self.settings[f][key] = value updated.append(f) ctx.master.addons.trigger(hooks.UpdateHook(updated))
def load_flows(self, flows: typing.Sequence[flow.Flow]) -> None: """ Replay server responses from flows. """ self.flowmap = {} for f in flows: if isinstance(f, http.HTTPFlow): lst = self.flowmap.setdefault(self._hash(f), []) lst.append(f) ctx.master.addons.trigger(hooks.UpdateHook([]))
async def handle_lifecycle(self, event: hooks.Hook): """ Handle a lifecycle event. """ message = event.args()[0] await self.trigger_event(event) if isinstance(message, flow.Flow): await self.trigger_event(hooks.UpdateHook([message]))
def mark(self, flows: typing.Sequence[flow.Flow], boolean: bool) -> None: """ Mark flows. """ updated = [] for i in flows: if i.marked != boolean: i.marked = boolean updated.append(i) ctx.master.addons.trigger(hooks.UpdateHook(updated))
def revert(self, flows: typing.Sequence[flow.Flow]) -> None: """ Revert flow changes. """ updated = [] for f in flows: if f.modified(): f.revert() updated.append(f) ctx.log.alert("Reverted %s flows." % len(updated)) ctx.master.addons.trigger(hooks.UpdateHook(updated))
def kill(self, flows: typing.Sequence[flow.Flow]) -> None: """ Kill running flows. """ updated = [] for f in flows: if f.killable: f.kill() updated.append(f) ctx.log.alert("Killed %s flows." % len(updated)) ctx.master.addons.trigger(hooks.UpdateHook(updated))
def setvalue_toggle(self, flows: typing.Sequence[mitmproxy.flow.Flow], key: str) -> None: """ Toggle a boolean value in the settings store, setting the value to the string "true" or "false". """ updated = [] for f in flows: current = self.settings[f].get("key", "false") self.settings[f][key] = "false" if current == "true" else "true" updated.append(f) ctx.master.addons.trigger(hooks.UpdateHook(updated))
def mark(self, flows: typing.Sequence[flow.Flow], marker: mitmproxy.types.Marker) -> None: """ Mark flows. """ updated = [] if marker not in emoji.emoji: raise exceptions.CommandError(f"invalid marker value") for i in flows: i.marked = marker updated.append(i) ctx.master.addons.trigger(hooks.UpdateHook(updated))
def decode(self, flows: typing.Sequence[flow.Flow], part: str) -> None: """ Decode flows. """ updated = [] for f in flows: p = getattr(f, part, None) if p: f.backup() p.decode() updated.append(f) ctx.master.addons.trigger(hooks.UpdateHook(updated)) ctx.log.alert("Decoded %s flows." % len(updated))
def encode_toggle(self, flows: typing.Sequence[flow.Flow], part: str) -> None: """ Toggle flow encoding on and off, using deflate for encoding. """ updated = [] for f in flows: p = getattr(f, part, None) if p: f.backup() current_enc = p.headers.get("content-encoding", "identity") if current_enc == "identity": p.encode("deflate") else: p.decode() updated.append(f) ctx.master.addons.trigger(hooks.UpdateHook(updated)) ctx.log.alert("Toggled encoding on %s flows." % len(updated))
def encode( self, flows: typing.Sequence[flow.Flow], part: str, encoding: str, ) -> None: """ Encode flows with a specified encoding. """ updated = [] for f in flows: p = getattr(f, part, None) if p: current_enc = p.headers.get("content-encoding", "identity") if current_enc == "identity": f.backup() p.encode(encoding) updated.append(f) ctx.master.addons.trigger(hooks.UpdateHook(updated)) ctx.log.alert("Encoded %s flows." % len(updated))
def clear(self) -> None: """ Stop server replay. """ self.flowmap = {} ctx.master.addons.trigger(hooks.UpdateHook([]))