Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom template option #41

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bin/http_request_translator
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ def take_arguments():
help="Interactive mode: read raw HTTP request from keyboard.")
parser.add_argument(
'--data', '-d',
help='Add the data that you want to send along with the header')
help='Add the data that you want to send along with the header.')
parser.add_argument(
'--custom-template', '-t',
help='Add the path of the custom template you want to provide.')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add proper name for the custom template option ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid 'you'. Keep it broad like "Specify path for custom templates."

request_group.add_argument(
'--request', '-r',
help='Input the HTTP request')
Expand Down
26 changes: 17 additions & 9 deletions http_request_translator/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from importlib import import_module

from .url import get_url, check_valid_url
from .util import exists_global_custom_template, get_global_custom_template


class AbstractScript(object):
Expand All @@ -27,16 +28,17 @@ class AbstractScript(object):
code_search = ''
code_nosearch = ''

def __init__(self, headers=None, details=None, search=None):
def __init__(self, headers=None, details=None, search=None, template=None):
"""Initialize the script generation.

:param list headers: Headers list containing fields like 'Host', 'User-Agent', etc.
:param dict details: Request specific details dictionary like body and method of the request.
:param str search: String to search for in the response to the request.
:param str template: Custom template path in dotted module format.

:raises ValueError: When url is invalid.
"""
self.load_attributes(self.__class__)
self.load_attributes(self.__class__, template)
self._script = ''
self.headers = headers
self.details = details
Expand Down Expand Up @@ -190,21 +192,27 @@ def encode_url(self, url):
return encoded_url

@staticmethod
def load_attributes(cls):
def load_attributes(cls, template=None):
"""Loads attributes to Script class from a given script's template

Imports the template file/module, assigns all the attributes defined in the template file to the given class.

:param class cls: Script class to which template is to be loaded.
:param str template: Custom template path in dotted module format.

:raises AttributeError: When __language__ attribute is not present.
"""
templates_path = "{}.templates".format(__name__.split('.', 1)[0])
if not hasattr(cls, '__language__'):
raise AttributeError("__language__ not found in class: {}, attributes cannot be loaded".format(cls.__name__))
template = import_module("{templates_path}.{class_template}".format(
templates_path=templates_path,
class_template=cls.__language__))
if template:
template = import_module(template)
elif exists_global_custom_template(cls.__language__):
template = get_global_custom_template(cls.__language__)
else:
templates_path = "{}.templates".format(__name__.split('.', 1)[0])
if not hasattr(cls, '__language__'):
raise AttributeError("__language__ not found in class: {}, attributes cannot be loaded".format(cls.__name__))
template = import_module("{templates_path}.{class_template}".format(
templates_path=templates_path,
class_template=cls.__language__))
attributes = (var for var in vars(template) if var.startswith('code_'))
for attr in attributes:
setattr(cls, attr, getattr(template, attr))
4 changes: 2 additions & 2 deletions http_request_translator/plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def get_script_class(script_name):
raise ValueError("The {} language is not supported.".format(script_name))


def generate_script(script, headers, details, search_string=None):
def generate_script(script, headers, details, search_string=None, template=None):
"""Returns the script code for the HTTP request passed in script language

:param str script: Name of the language for which script is to be generated
Expand All @@ -34,4 +34,4 @@ def generate_script(script, headers, details, search_string=None):
:rtype: `str`
"""
class_script = get_script_class(script.strip().lower())
return class_script(headers=headers, details=details, search=search_string).generate_script()
return class_script(headers=headers, details=details, search=search_string, template=template).generate_script()
2 changes: 1 addition & 1 deletion http_request_translator/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def process_arguments(args):
elif args.search_regex:
arg_option = args.search_regex
if len(script_list) == 0:
generated_code = generate_script('bash', headers, details, arg_option)
generated_code = generate_script('bash', headers, details, arg_option, args.custom_template)
print(generated_code)
else:
for script in script_list:
Expand Down
15 changes: 15 additions & 0 deletions http_request_translator/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from importlib import import_module
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move that import after?

import os
import re
import sys


# Blindy copied from: https://gist.github.com/mnordhoff/2213179
Expand All @@ -7,3 +10,15 @@
re_ipv6_address = re.compile('^(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){,6}[0-9A-Fa-f]{1,4})?::)$')
# Homebrew
re_domain = re.compile(r'^(?:(?:[A-Z](?:[A-Z-]{0,61}[A-Z])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|)$', re.IGNORECASE)

DEFAULT_CUSTOM_TEMPLATE_PATH = os.environ.get('DEFAULT_CUSTOM_TEMPLATE_PATH', '~/.config/translator/templates')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point we will need to implement a configuration file for the project. Maybe for later? Should we create an issue for that and add some TODO here like:

# TODO: Move it to configuration file (See issue #xxx)

What do you think?

DEFAULT_CUSTOM_TEMPLATE_PATH = DEFAULT_CUSTOM_TEMPLATE_PATH.replace('~', os.environ.get('HOME', ''))


def exists_global_custom_template(language):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the name of that function. Could you add a docstring as well?

return os.path.exists(os.path.join(DEFAULT_CUSTOM_TEMPLATE_PATH, "{}.py".format(language)))


def get_global_custom_template(language):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the name of that function. Could you add a docstring as well for this one?

sys.path.insert(0, DEFAULT_CUSTOM_TEMPLATE_PATH)
return import_module(language)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if there is an exception because of a dodgy template?