Prompt user on existing directory (#57)

* added tests and check_scan_directory

* added documentation; closes #30
This commit is contained in:
epi052
2020-04-30 08:19:56 -07:00
committed by GitHub
parent f1c1868a6e
commit 2ecdf4319a
5 changed files with 282 additions and 78 deletions

View File

@@ -2,11 +2,13 @@
# stdlib imports
import os
import sys
import time
import shlex
import shutil
import pickle
import selectors
import tempfile
import textwrap
import selectors
import threading
import subprocess
import webbrowser
@@ -116,10 +118,11 @@ class ReconShell(cmd2.Cmd):
self.selectorloop = None
self.continue_install = True
self.prompt = DEFAULT_PROMPT
self.tools_dir = Path(defaults.get("tools-dir"))
self._initialize_parsers()
Path(defaults.get("tools-dir")).mkdir(parents=True, exist_ok=True)
self.tools_dir.mkdir(parents=True, exist_ok=True)
Path(defaults.get("database-dir")).mkdir(parents=True, exist_ok=True)
# register hooks to handle selector loop start and cleanup
@@ -207,6 +210,47 @@ class ReconShell(cmd2.Cmd):
self.async_alert(style(f"[+] {words[5].split('_')[0]} complete!", fg="bright_green"))
def check_scan_directory(self, directory):
""" Determine whether or not the results-dir about to be used already exists and prompt the user accordingly.
Args:
directory: the directory passed to ``scan ... --results-dir``
"""
directory = Path(directory)
if directory.exists():
term_width = shutil.get_terminal_size((80, 20)).columns
warning_msg = (
f"[*] Your results-dir ({str(directory)}) already exists. Subfolders/files may tell "
f"the pipeline that the associated Task is complete. This means that your scan may start "
f"from a point you don't expect. Your options are as follows:"
)
for line in textwrap.wrap(warning_msg, width=term_width, subsequent_indent=" "):
self.poutput(style(line, fg="bright_yellow"))
option_one = (
"Resume existing scan (use any existing scan data & only attempt to scan what isn't already done)"
)
option_two = "Remove existing directory (scan starts from the beginning & all existing results are removed)"
option_three = "Save existing directory (your existing folder is renamed and your scan proceeds)"
answer = self.select([("Resume", option_one), ("Remove", option_two), ("Save", option_three)])
if answer == "Resume":
self.poutput(style(f"[+] Resuming scan from last known good state.", fg="bright_green"))
elif answer == "Remove":
shutil.rmtree(Path(directory))
self.poutput(style(f"[+] Old directory removed, starting fresh scan.", fg="bright_green"))
elif answer == "Save":
current = time.strftime("%Y%m%d-%H%M%S")
directory.rename(f"{directory}-{current}")
self.poutput(
style(f"[+] Starting fresh scan. Old data saved as {directory}-{current}", fg="bright_green")
)
@cmd2.with_argparser(scan_parser)
def do_scan(self, args):
""" Scan something.
@@ -221,6 +265,8 @@ class ReconShell(cmd2.Cmd):
style(f"[!] You are not connected to a database; run database attach before scanning", fg="bright_red")
)
self.check_scan_directory(args.results_dir)
self.poutput(
style(
"If anything goes wrong, rerun your command with --verbose to enable debug statements.",
@@ -234,7 +280,7 @@ class ReconShell(cmd2.Cmd):
scans = get_scans()
# command is a list that will end up looking something like what's below
# luigi --module pipeline.recon.web.webanalyze WebanalyzeScan --target-file tesla --top-ports 1000 --interface eth0
# luigi --module pipeline.recon.web.webanalyze WebanalyzeScan --target abc.com --top-ports 100 --interface eth0
command = ["luigi", "--module", scans.get(args.scantype)[0]]
tgt_file_path = None
@@ -281,7 +327,7 @@ class ReconShell(cmd2.Cmd):
# imported tools variable is in global scope, and we reassign over it later
global tools
persistent_tool_dict = Path(defaults.get("tools-dir")) / ".tool-dict.pkl"
persistent_tool_dict = self.tools_dir / ".tool-dict.pkl"
if args.tool == "all":
# show all tools have been queued for installation
@@ -299,6 +345,7 @@ class ReconShell(cmd2.Cmd):
if persistent_tool_dict.exists():
tools = pickle.loads(persistent_tool_dict.read_bytes())
print(args.tool)
if tools.get(args.tool).get("dependencies"):
# get all of the requested tools dependencies