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

feat: add windows-specific installers for some tools #253

Open
wants to merge 3 commits into
base: main
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
46 changes: 34 additions & 12 deletions fsociety/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
format_tools,
module_name,
prompt,
run_tool,
set_readline,
)

Expand Down Expand Up @@ -99,22 +100,29 @@ def print_menu_items():
console.print(Columns(cols, equal=True, expand=True))

for key in BUILTIN_FUNCTIONS:
print()
console.print(key, style="command")
console.command(f"\n{key}")


def agreement():
while not config.getboolean("fsociety", "agreement"):
clear_screen()
console.print(TERMS, style="bold yellow")
agree = input("You must agree to our terms and conditions first (Y/n) ")
if agree.lower()[0] == "y":
console.input_error(TERMS)
agree = input("You must agree to our terms and conditions first (y/N) ")
if len(agree) and agree[0].lower() == "y":
config.set("fsociety", "agreement", "true")


subcommands = list()
for item in MENU_ITEMS:
items[module_name(item)] = item

for tool in item.__tools__:
subcommands.append(
{
"parent": item.__name__.split(".")[-1],
"tool": tool,
"name": tool.__str__(),
}
)
commands = list(items.keys()) + list(BUILTIN_FUNCTIONS.keys())


Expand All @@ -123,19 +131,33 @@ def mainloop():
console.print(choice(BANNERS), style="red", highlight=False)
print_menu_items()
selected_command = input(prompt()).strip()

def sub_command_has(sbc):
return sbc["name"] == selected_command

if not selected_command or (selected_command not in commands):
console.print("Invalid Command", style="bold yellow")
return
try:
matches = list(filter(sub_command_has, subcommands))
subcommand = None
if len(matches) > 0:
subcommand = matches[0]
if subcommand is not None:
# execute parent cli, pass subcmd.name -> cli
return run_tool(subcommand["tool"], subcommand["name"])
return console.input_error("Invalid Command", True)
except StopIteration:
# looks like we didn't find a subcommand, either
return console.input_error("Invalid Command", True)
except Exception as error:
return console.handle_error(error)
if selected_command in BUILTIN_FUNCTIONS:
func = BUILTIN_FUNCTIONS.get(selected_command)
return func()
try:
func = items[selected_command].cli
return func()
except Exception as error:
console.print(str(error))
console.print_exception()
return
return console.handle_error(error)


def info():
Expand All @@ -162,7 +184,7 @@ def interactive():
set_readline(commands)
mainloop()
except KeyboardInterrupt:
console.print("\nExitting...")
console.print("\nExiting...")
write_config(config)
sys.exit(0)

Expand Down
81 changes: 79 additions & 2 deletions fsociety/console.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from rich.console import Console
from enum import Enum

from rich.console import Console as RichConsole
from rich.theme import Theme
from rich.traceback import install

from fsociety.core.config import get_config

config = get_config()

# Install Traceback
install()

Expand All @@ -10,6 +16,77 @@
{
"command": "black on white",
"warning": "bold yellow",
"error": "bold red",
"info": "bold blue",
"debug": "bright_black",
"success": "bold green on green",
}
)
console = Console(theme=fsociety_theme)


class ConsoleLogLevel(Enum):
DEBUG = "debug"
INFO = "info"
ERROR = "error"
WARNING = "warning"


def input_wait():
input("\nPress [ENTER] to continue... ")


class Console(RichConsole):
"""Console class for fsociety"""

log_level: ConsoleLogLevel = ConsoleLogLevel.ERROR

def __init__(self, log_level: ConsoleLogLevel = ConsoleLogLevel.ERROR):
super().__init__(theme=fsociety_theme)
self.log_level = ConsoleLogLevel(log_level)

def set_log_level(self, level: str):
self.log_level = ConsoleLogLevel(level)

def debug(self, message: str, error: Exception = None, wait_input: bool = False):
if self.log_level == ConsoleLogLevel.DEBUG:
self.print(message, style="debug")
if error:
self.print_exception()
if wait_input:
input_wait()

def info(self, message: str, wait_input: bool = False):
if self.log_level in [ConsoleLogLevel.DEBUG, ConsoleLogLevel.INFO]:
self.print(message, style="info")
if wait_input:
input_wait()

def input_error(self, message: str, wait_input: bool = False):
self.print(message, style="warning")
if wait_input:
input_wait()

def error(self, message: str, wait_input: bool = False):
self.print(message, style="error")
if self.log_level == ConsoleLogLevel.DEBUG:
self.print_exception()
if wait_input:
input_wait()

def handle_error(self, error: Exception):
self.error(str(error))
if self.log_level == ConsoleLogLevel.DEBUG:
self.print_exception()
input_wait()

def success(self, message: str):
self.print(message, style="success")
input_wait()

def command(self, message: str):
self.print(message, style="command")


default_log_level = config.get("fsociety", "log_level")

console = Console(ConsoleLogLevel(default_log_level))
2 changes: 2 additions & 0 deletions fsociety/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
elif platform.startswith("linux") or platform.startswith("freebsd"):
CURRENT_PLATFORM = distro.like()


INSTALL_DIR = os.path.join(str(Path.home()), ".fsociety")
CONFIG_FILE = os.path.join(INSTALL_DIR, "fsociety.cfg")
GITHUB_PATH = "fsociety-team/fsociety"
Expand All @@ -26,6 +27,7 @@
"os": CURRENT_PLATFORM,
"host_file": "hosts.txt",
"usernames_file": "usernames.txt",
"log_level": "info",
}


Expand Down
44 changes: 19 additions & 25 deletions fsociety/core/menu.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import shutil
from typing import Iterable

from rich import box
Expand Down Expand Up @@ -74,8 +73,20 @@ def prompt(path="", base_path="~"):
return f"\nfsociety {encoded_path}# "


def input_wait():
input("\nPress [ENTER] to continue... ")
def run_tool(tool, selected_tool: str):
if hasattr(tool, "install") and not tool.installed():
tool.install()
try:
response = tool.run()
if response and response > 0 and response != 256:
console.error(f"{selected_tool} returned a non-zero exit code")
if hasattr(tool, "install") and confirm("Do you want to reinstall?"):
os.chdir(INSTALL_DIR)
tool.uninstall()
tool.install()
console.success(f"{selected_tool} completed")
except KeyboardInterrupt:
return


def tools_cli(name, tools, links=True):
Expand All @@ -96,37 +107,20 @@ def tools_cli(name, tools, links=True):
table.add_row(*args)

console.print(table)
console.print("back", style="command")
console.command("back")
set_readline(list(tools_dict.keys()) + BACK_COMMANDS)
selected_tool = input(prompt(name.split(".")[-2])).strip()
if selected_tool not in tools_dict:
if selected_tool in BACK_COMMANDS:
return
if selected_tool == "exit":
raise KeyboardInterrupt
console.print("Invalid Command", style="bold yellow")
console.warn("Invalid Command", True)
return tools_cli(name, tools, links)
tool = tools_dict.get(selected_tool)
if hasattr(tool, "install") and not tool.installed():
tool.install()
try:
response = tool.run()
if response and response > 0 and response != 256:
console.print(
f"{selected_tool} returned a non-zero exit code", style="bold red"
)
if hasattr(tool, "install") and confirm("Do you want to reinstall?"):
os.chdir(INSTALL_DIR)
shutil.rmtree(tool.full_path)
tool.install()
except KeyboardInterrupt:
return

return input_wait()
return run_tool(tool, selected_tool)


def confirm(message="Do you want to?"):
response = input(f"{message} (y/n): ").lower()
if response:
return response[0] == "y"
return False
agree = input(f"{message} (y/N): ")
return len(agree) and agree[0].lower() == "y"
41 changes: 40 additions & 1 deletion fsociety/core/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,39 @@ def clone(self, overwrite: bool = False) -> str:
raise CloneError(f"{self.full_path} not found")
return self.full_path

def uninstallable(self) -> bool:
if self.install_options:
install = self.install_options
target_os = config.get("fsociety", "os")
if isinstance(install, dict):
if target_os == "macos" and "brew" in install and which("brew"):
return True
elif target_os == "windows" and "winget" in install and which("winget"):
return True
elif target_os == "windows" and "scoop" in install and which("scoop"):
return True
return False

def uninstall(self) -> None:
if self.install_options:
install = self.install_options
target_os = config.get("fsociety", "os")
command = "exit 1"
if isinstance(install, dict):
if "brew" in install and which("brew"):
brew_opts = install.get("brew")
command = f"brew uninstall {brew_opts}"
elif target_os == "windows" and "winget" in install and which("winget"):
winget_opts = install.get("winget")
command = f"winget uninstall {winget_opts}"
elif target_os == "windows" and "scoop" in install and which("scoop"):
scoop_opts = install.get("scoop")
command = f"scoop uninstall {scoop_opts}"
if command == "exit 1":
rmtree(self.full_path)
else:
os.system(command)

def install(self, no_confirm: bool = False, clone: bool = True) -> None:
if no_confirm or not confirm(
f"\nDo you want to install https://github.com/{self.path}?"
Expand Down Expand Up @@ -175,7 +208,13 @@ def install(self, no_confirm: bool = False, clone: bool = True) -> None:
command = f"mkdir {self.full_path} && {command} && chmod +x {self.full_path}/{self.name}"
elif "brew" in install and which("brew"):
brew_opts = install.get("brew")
command = f"brew {brew_opts}"
command = f"brew install {brew_opts}"
elif target_os == "windows" and "winget" in install and which("winget"):
winget_opts = install.get("winget")
command = f"winget install {winget_opts}"
elif target_os == "windows" and "scoop" in install and which("scoop"):
scoop_opts = install.get("scoop")
command = f"scoop install {scoop_opts}"
elif target_os in install and target_os in self.scriptable_os:
command = str(install[target_os])
else:
Expand Down
2 changes: 1 addition & 1 deletion fsociety/information_gathering/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cli import __tools__, cli

__all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
__all__ = ["cli", "__tools__", "__name__"] + [str(tool) for tool in __tools__]
2 changes: 1 addition & 1 deletion fsociety/networking/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cli import __tools__, cli

__all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
__all__ = ["cli", "__tools__", "__name__"] + [str(tool) for tool in __tools__]
2 changes: 1 addition & 1 deletion fsociety/networking/bettercap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(self):
install={
"linux": "sudo apt install golang git build-essential libpcap-dev libusb-1.0-0-dev libnetfilter-queue-dev; go get -u github.com/bettercap/bettercap",
"arch": "sudo pacman -Sy bettercap",
"brew": "install bettercap",
"brew": "bettercap",
},
description="Swiss army knife for network attacks and monitoring",
)
Expand Down
4 changes: 3 additions & 1 deletion fsociety/networking/nmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ def __init__(self):
path="nmap/nmap",
install={
"arch": "sudo pacman -Sy nmap",
"brew": "install nmap",
"brew": "nmap",
"linux": "sudo apt-get install nmap",
"scoop": "nmap extras/vcredist2008",
"winget": "nmap",
},
description="the Network Mapper",
)
Expand Down
2 changes: 1 addition & 1 deletion fsociety/obfuscation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cli import __tools__, cli

__all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
__all__ = ["cli", "__tools__", "__name__"] + [str(tool) for tool in __tools__]
2 changes: 1 addition & 1 deletion fsociety/passwords/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cli import __tools__, cli

__all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
__all__ = ["cli", "__tools__", "__name__"] + [str(tool) for tool in __tools__]
2 changes: 1 addition & 1 deletion fsociety/web_apps/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .cli import __tools__, cli

__all__ = ["cli", "__tools__"] + [str(tool) for tool in __tools__]
__all__ = ["cli", "__tools__", "__name__"] + [str(tool) for tool in __tools__]
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
python_version = 3.6
python_version = 3.8
files = fsociety

[mypy-git.*]
Expand Down
Loading