--- /dev/null
+# Hector
+
+__Hector__ is an addon for the excellent [mitmproxy](https://mitmproxy.org)
+application, which captures and generates API documentation according to the
+[OpenAPI Specification](https://swagger.io/specification/).
+
+
+## Setup
+
+Create a virtual environment using your preferred method and install
+dependencies. Python 3 is strongly preferred.
+
+```shell
+$ python3 -mvenv ~/env/hector
+$ pip install -r requirements.txt
+```
+
+
+## Usage
+
+```shell
+$ mitmdump -s ./hector.py --set hector_template=template.yaml \
+ --set hector_input=input.yaml \
+ --set hector_output=output.yaml
+```
+
+__hector__ will write swagger for every host accessed during your mitmproxy
+session. At the end of the session all swagger data will be written to a single
+yaml file, separated by `--` per host.
+
+
+## Options
+
+### hector_template _(optional)_
+
+This option specifies the base yaml that will be used by __hector__. You may
+provide your own template, or the default, `hector_template.yaml` will be used
+
+### hector output _(optional)_
+
+This option specifies the file to which the swagger yaml will be written at the
+end of the session. Default: `output.yaml`
+
+### hector input _(optional)_
+
+This option allows you to load an existing swagger yaml, perhaps to resume a
+previous session. Default: `None`
+
+
+## TODO
+
+* Add parameter and response details
+* Add option to filter by host or regex
+* Optionally write to multiple files instead of just one
+* Post-process swagger to collapse on base-path
--- /dev/null
+import copy
+import yaml
+from mitmproxy import ctx
+
+
+class Hector:
+
+ def __init__(self):
+ self._output = {}
+
+ def load(self, loader):
+ loader.add_option(
+ name='hector_template',
+ typespec=str,
+ default='./hector_template.yaml',
+ help='Yaml file to be used as base for swagger output.')
+
+ loader.add_option(
+ name='hector_output',
+ typespec=str,
+ default='./output.yaml',
+ help='Yaml file where the generated swagger will be output.')
+
+ loader.add_option(
+ name='hector_input',
+ typespec=str,
+ default='',
+ help='Swagger yaml file to be loaded and added to.')
+
+ def running(self):
+ with open(ctx.options.hector_template) as template:
+ self._template = yaml.load(template, Loader=yaml.Loader)
+
+ if ctx.options.hector_input != '':
+ with open(ctx.options.hector_input, 'r') as swagger:
+ for doc in yaml.load_all(swagger, Loader=yaml.Loader):
+ print(doc)
+ self._output[doc['host']] = doc
+
+ def done(self):
+ with open(ctx.options.hector_output, 'w') as output:
+ print(yaml.dump_all(self._output.values(),
+ Dumper=yaml.Dumper), file=output)
+
+ def request(self, flow):
+ request = flow.request
+
+ if request.host not in self._output:
+ self._output[request.host] = copy.deepcopy(self._template)
+
+ target = self._output[request.host]
+ target['host'] = request.host
+
+ if request.scheme not in target['schemes']:
+ target['schemes'].append(request.scheme)
+
+ if request.path not in target:
+ target['paths'][request.path] = {}
+
+
+addons = [
+ Hector()
+]