Skip to content

Commit

Permalink
refactor: edit codebase according to PEP (#153)
Browse files Browse the repository at this point in the history
* refactoring

* string pep reformat

* arg pep reformat

* edit doc string

* remove unused import

* Add CI workflow (#149)

Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>

* Format the workflow file

* Rename workflow file

* refactoring

* string pep reformat

* arg pep reformat

* edit doc string

* remove unused import

* update exceptions

* update commands & web

* lint ignore E501

* ignore useless rules

* remove whitespaces

---------

Co-authored-by: KacperNapierski <80033411+KacperNapierski@users.noreply.github.com>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
  • Loading branch information
3 people committed Sep 22, 2023
1 parent bb6bc5f commit a8a4976
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ jobs:

- name: "flake8 python linter"
uses: py-actions/flake8@v2
with:
args: "--max-line-length=120 --ignore=E501,E226,W504"

setup_linux:
name: "Linux setup"
Expand Down
3 changes: 1 addition & 2 deletions graphenex/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from graphenex.core.web import run_server
from graphenex import __version__


logger = GraphenexLogger('Graphenex')


Expand All @@ -19,7 +18,7 @@ def main():
else:
if args['open']:
logger.warn("[--open] argument is unnecessary. " +
"Use with [-w] or [--web].")
"Use with [-w] or [--web].")
start_cli()


Expand Down
110 changes: 56 additions & 54 deletions graphenex/core/cli/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from graphenex.core.utils.logcl import GraphenexLogger
from graphenex.core.cli.help import Help


logger = GraphenexLogger(__name__)


Expand Down Expand Up @@ -51,6 +50,7 @@ def do_use(self, arg):
def select_module_msg():
logger.info(f"\"{self.module}\" module selected. Use 'harden' command " +
"for hardening or use 'info' for more information.")

if not arg:
logger.warn("'use' command takes 1 argument.")
return
Expand Down Expand Up @@ -86,8 +86,7 @@ def complete_use(self, text, line, begidx, endidx):
if '/' in mline:
# title() -> given module string for getting rid of
# the case sensitivity
mline = mline.split('/')[0].lower() + "/" + \
mline.split('/')[1].title()
mline = mline.split('/')[0].lower() + "/" + mline.split('/')[1].title()
offs = len(mline) - len(text)
# Get completed text with namespace
comp_text = [s[offs:] for s in avb_modules if s.startswith(mline)]
Expand All @@ -108,7 +107,7 @@ def do_info(self, arg):
if self.module:
module = self.modules[self.namespace][self.module]
print(f"\n\tNamespace: {self.namespace}\n\tModule: {module.name}\n\t" +
f"Description: {module.desc}\n" + f"\tCommand: {module.command}\n")
f"Description: {module.desc}\n" + f"\tCommand: {module.command}\n")
else:
logger.error('No module selected.')

Expand Down Expand Up @@ -147,7 +146,7 @@ def do_list(self, arg):
max_width = table.column_max_width(1)

if self.namespace:
for name, module in self.modules[self.namespace].items():
for name, module in self.modules[self.namespace].items():
wrapped = '\n'.join(textwrap.wrap(module.desc, max_width - 40))
table.table_data.append(
[self.namespace + "/" + name, wrapped])
Expand All @@ -157,7 +156,7 @@ def do_list(self, arg):
wrapped = '\n'.join(textwrap.wrap(module.desc, max_width - 40))
table.table_data.append(
[k + "/" + name, wrapped])

print(table.table)

def do_back(self, arg):
Expand Down Expand Up @@ -234,28 +233,28 @@ def save_mod_json(data):
mod_namespace = prompt(mod_question)
try:
mod_ns = mod_namespace['mod_ns']
except:
except KeyError:
pass
# Assigning property to the ModuleNameValidation class to
# Assigning property to the ModuleNameValidation class to
# access modules within the selected namespace.
ModuleNameValidation.modules = self.modules[mod_ns].keys() \
if mod_ns in self.modules.keys() else []
mod_details = prompt(mod_questions)
mod_dict = {
"name": mod_details['mod_name'].title(),
"desc": mod_details['mod_desc'],
"command": mod_details['mod_cmd'],
"require_superuser": mod_details['mod_su'],
"target_os": "win" if check_os() else "linux"
}
"name": mod_details['mod_name'].title(),
"desc": mod_details['mod_desc'],
"command": mod_details['mod_cmd'],
"require_superuser": mod_details['mod_su'],
"target_os": "win" if check_os() else "linux"
}
try:
data[mod_ns.lower()].append(mod_dict)
except:
except KeyError:
data.update({mod_ns.lower(): [mod_dict]})
# Write the updated modules.json
save_mod_json(data)
logger.info("Module added successfully. Use 'list' " + \
"command to see available modules.")
logger.info("Module added successfully. Use 'list' " +
"command to see available modules.")

# EDIT & REMOVE
elif choice['option'] == "Edit module" or choice['option'] == "Remove module":
Expand Down Expand Up @@ -310,7 +309,7 @@ def save_mod_json(data):
# Write the updated modules.json
save_mod_json(data)
logger.info("Module updated successfully. (" + selected_ns + "/" +
selected_mod + ":" + selected_prop + ")")
selected_mod + ":" + selected_prop + ")")

# REMOVE
else:
Expand All @@ -327,11 +326,11 @@ def save_mod_json(data):

def do_preset(self, arg):
"""Show/execute the hardening module presets"""

presets = get_presets()
if arg:
modules = [preset['modules'] for preset in presets \
if preset['name'] == arg]
modules = [preset['modules'] for preset in presets
if preset['name'] == arg]
if len(modules) == 0:
logger.error(f"Preset not found: '{arg}'")
return
Expand All @@ -345,7 +344,7 @@ def do_preset(self, arg):
]
try:
conf_mod = prompt(confirm_prompt)['confirm']
except:
except KeyError:
return
# Main module loop
for module in modules:
Expand All @@ -356,7 +355,7 @@ def do_preset(self, arg):
# Select the module if it equals to the module in
# the preset or equals to 'all'
if module.split("/")[1].lower() == "all" or \
module.split("/")[1].lower() == name.lower():
module.split("/")[1].lower() == name.lower():
# Select the module
self.module = str(mod)
# Show module information
Expand All @@ -367,19 +366,19 @@ def do_preset(self, arg):
else:
# Ask for permission for executing the command
exec_conf = prompt([{
'type': 'confirm',
'name': 'confirm',
'message': 'Execute the hardening command?',
'type': 'confirm',
'name': 'confirm',
'message': 'Execute the hardening command?',
}])
# Execute the command or cancel
try:
if exec_conf['confirm']:
self.do_harden(None)
else:
raise Exception("Cancelled by user.")
except:
logger.info("Hardening cancelled. " + \
f"({self.namespace}/{self.module})")
except Exception:
logger.info("Hardening cancelled. " +
f"({self.namespace}/{self.module})")
# Go back from the selected module and namespace
self.module = ""
self.namespace = ""
Expand All @@ -395,14 +394,14 @@ def do_preset(self, arg):
mods = ""
for module in preset['modules'][:-1]:
mods += '\n'.join(textwrap.wrap(module, max_width - 40)) + '\n'
mods += '\n'.join(textwrap.wrap(preset['modules'][-1], max_width-40))
mods += '\n'.join(textwrap.wrap(preset['modules'][-1], max_width - 40))
table.table_data.append([preset['name'], mods])
# Show the table
if len(table.table_data) > 1:
print(table.table)
else:
logger.warn(f"No presets found in {mod_json_file}")

def complete_preset(self, text, line, begidx, endidx):
"""Complete preset command"""

Expand All @@ -416,7 +415,7 @@ def do_web(self, arg):

from graphenex.core.web import run_server, app
app.config['ACCESS_TOKEN'] = secrets.token_urlsafe(6)
run_server({"host_port":arg} if arg else None, False)
run_server({"host_port": arg} if arg else None, False)

def do_harden(self, arg):
"""Execute the hardening command"""
Expand All @@ -439,8 +438,16 @@ def do_harden(self, arg):
except Exception as e:
logger.error("Failed to execute hardening command. " + str(e))

def do_exit(self, arg):
"Exit interactive shell"
def do_EOF(self, arg):
"""EOF exit"""

print()
self.do_exit(arg)
return True

@staticmethod
def do_exit(arg):
"""Exit interactive shell"""

exit_msgs = [
"Bye!",
Expand All @@ -458,13 +465,6 @@ def do_exit(self, arg):
logger.info(random.choice(exit_msgs))
return True

def do_EOF(self, arg):
"""EOF exit"""

print()
self.do_exit(arg)
return True

@staticmethod
def do_clear(arg):
"""Clear the terminal"""
Expand All @@ -477,18 +477,20 @@ def default(line):

logger.error("Command not found.")


class ModuleNameValidation(Validator):
def validate(self, document):
"""Validate the module name for the prompt"""

if not re.match(r'^\w+$', document.text):
raise ValidationError(
message='Enter a valid module name',
cursor_position=len(document.text))
elif document.text.lower() in [module.lower() for module in self.modules]:
raise ValidationError(
message="Try a different name, this module name is not available.",
cursor_position=len(document.text))
def validate(self, document):
"""Validate the module name for the prompt"""

if not re.match(r'^\w+$', document.text):
raise ValidationError(
message='Enter a valid module name',
cursor_position=len(document.text))
elif document.text.lower() in [module.lower() for module in self.modules]:
raise ValidationError(
message="Try a different name, this module name is not available.",
cursor_position=len(document.text))


class NamespaceValidation(Validator):

Expand All @@ -499,5 +501,5 @@ def validate(document):
namespaces = get_forbidden_namespaces()
if document.text.lower() in [namespace.lower() for namespace in namespaces]:
raise ValidationError(
message="You do not have permission to access this namespace.",
cursor_position=len(document.text))
message="You do not have permission to access this namespace.",
cursor_position=len(document.text))
17 changes: 8 additions & 9 deletions graphenex/core/cli/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from graphenex.core.utils.logcl import GraphenexLogger


logger = GraphenexLogger(__name__)


Expand All @@ -19,19 +18,19 @@ def do_help(self, arg):
func = getattr(self, f"do_{arg}")
if f"help_{arg}" in dir(self):
getattr(self, f"help_{arg}")()
else:
else:
doc = func.__doc__ if func.__doc__ else "No description"
print(f"\n\tSyntax: {func.__name__[3:]}\n\t{doc}\n")
except AttributeError:
logger.error(f"Cannot find help method for \"{arg}\".")
else:
else:
# Create table for all commands
help_table = [['Command', 'Description']]
# In all methods and attributes
for name in self.get_names():
# Get do_* function
if name[:3] == "do_" and name != "do_EOF":
docstr = getattr(self, name).__doc__
docstr = getattr(self, name).__doc__
doc = docstr if docstr else "No description"
help_table.append([getattr(self, name).__name__[3:], doc])
print(AsciiTable(help_table).table)
Expand All @@ -44,20 +43,20 @@ def message(syntax, content):

def help_switch(self):
self.message(syntax="switch [module]",
content="Switch between modules")
content="Switch between modules")

def help_search(self):
self.message(syntax="search [query]",
content="Search for module or namespace")
content="Search for module or namespace")

def help_use(self):
self.message(syntax="use [module]",
content="Use hardening module")
content="Use hardening module")

def help_web(self):
self.message(syntax="web [host:port]",
content="Start the web server")
content="Start the web server")

def help_preset(self):
self.message(syntax="preset [preset]",
content="Execute the hardening module preset")
content="Execute the hardening module preset")
2 changes: 1 addition & 1 deletion graphenex/core/cli/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def prompt(self):

def start_cli():
"""Start the command line interface"""

shell = Shell()
try:
shell.cmdloop()
Expand Down
2 changes: 1 addition & 1 deletion graphenex/core/hrd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ def __repr__(self):
return self.__str__()

def execute_command(self):
return getattr(self, self.target_os + "Exec").run_cmd(self.command)
return getattr(self, self.target_os + "Exec").run_cmd(self.command)
2 changes: 1 addition & 1 deletion graphenex/core/hrd/exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def run_cmd(self, cmd, shell=True):
"""
Executes the Windows command and returns it's output in UTF-8 format.
"""

result = subprocess.run(shlex.split(
cmd), stdout=subprocess.PIPE, shell=shell)
return result.stdout.decode('utf-8', 'replace')
2 changes: 1 addition & 1 deletion graphenex/core/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def is_admin():
try:
result = ctypes.windll.shell32.IsUserAnAdmin()
return result
except:
except Exception:
return False

if check_os():
Expand Down
2 changes: 1 addition & 1 deletion graphenex/core/utils/logcl.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self, name, level='INFO',
threadName=dict(color='green')
)
coloredlogs.install(level=self.level, fmt=self.format,
datefmt="%H:%M:%S", logger=self.logger,
datefmt="%H:%M:%S", logger=self.logger,
field_styles=FIELD_STYLES)

@staticmethod
Expand Down
Loading

0 comments on commit a8a4976

Please sign in to comment.