From 9a7cf8d848bdd6f62d025f746daac0b86f981f4d Mon Sep 17 00:00:00 2001 From: Aleksa Zatezalo Date: Fri, 26 Jul 2024 17:47:31 -0400 Subject: [PATCH 1/3] Text coloring functions combined. --- gato/attack/attack.py | 2 +- gato/cli/cli.py | 2 +- gato/cli/output.py | 58 +++++++++++++++++++---------------- gato/enumerate/enumerate.py | 2 +- gato/enumerate/recommender.py | 2 +- gato/search/search.py | 2 +- 6 files changed, 37 insertions(+), 31 deletions(-) diff --git a/gato/attack/attack.py b/gato/attack/attack.py index 4707519..0aa2685 100644 --- a/gato/attack/attack.py +++ b/gato/attack/attack.py @@ -77,7 +77,7 @@ def __setup_user_info(self): ) Output.info( "The GitHub Classic PAT has the following scopes: " - f'{Output.yellow(", ".join(self.user_perms["scopes"]))}' + f'{Output.text_color(", ".join(self.user_perms["scopes"]), 'yellow')}' ) return True diff --git a/gato/cli/cli.py b/gato/cli/cli.py index ef31f60..937fa7f 100644 --- a/gato/cli/cli.py +++ b/gato/cli/cli.py @@ -456,7 +456,7 @@ def configure_parser_attack(parser): parser.add_argument( "--file-name", "-fn", default="test", - help=f"Name of yaml file {Output.bright('without extension')} that will be\n" + help=f"Name of yaml file {Output.text_color('without extension', 'red')} that will be\n" "written as part of either attack type. Defaults to 'test'", type=StringType(64) ) diff --git a/gato/cli/output.py b/gato/cli/output.py index c0adaad..08a62a2 100644 --- a/gato/cli/output.py +++ b/gato/cli/output.py @@ -1,13 +1,10 @@ import json - -from gato.cli import (RED_DASH, GREEN_PLUS, GREEN_EXCLAIM, RED_EXCLAIM, - BRIGHT_DASH, YELLOW_EXCLAIM, SPLASH, YELLOW_DASH) - - from colorama import Style, Fore +from gato.cli import (RED_DASH, GREEN_PLUS, GREEN_EXCLAIM, RED_EXCLAIM, BRIGHT_DASH, YELLOW_EXCLAIM, SPLASH, YELLOW_DASH) class Singleton (type): + _instances = {} def __call__(cls, *args, **kwargs): @@ -17,13 +14,12 @@ def __call__(cls, *args, **kwargs): ) return cls._instances[cls] - class Output(metaclass=Singleton): def __init__(self, silent: bool, color: bool): + self.silent = silent self.color = color - self.red_dash = RED_DASH if color else '[-]' self.red_explain = RED_EXCLAIM if color else '[!]' self.green_plus = GREEN_PLUS if color else '[+]' @@ -31,6 +27,10 @@ def __init__(self, silent: bool, color: bool): self.bright_dash = BRIGHT_DASH if color else '-' self.yellow_exclaim = YELLOW_EXCLAIM if color else "[!]" self.yellow_dash = YELLOW_DASH if color else "[-]" + + ####################### + ## FileIO Functions ## + ####################### @classmethod def write_json(cls, execution_wrapper, output_json): @@ -43,17 +43,23 @@ def write_json(cls, execution_wrapper, output_json): Returns: True if successful, false otherwise. """ + if execution_wrapper.user_details: with open(output_json, 'w') as json_out: json_out.write( json.dumps(execution_wrapper.toJSON(), indent=4) ) return True + + ####################### + ## STDOUT Functions ## + ####################### @classmethod def splash(cls): """Prints the Gato mascot. """ + if not Output().silent: print(SPLASH) @@ -64,6 +70,7 @@ def error(cls, message: str): Args: message (str): Message to format. """ + print(f"{Output().red_dash} {message}") @classmethod @@ -73,6 +80,7 @@ def info(cls, message: str, end='\n', flush=False): Args: message (str): The message to print. """ + print(f"{Output().green_plus} {message}", end=end, flush=flush) @classmethod @@ -82,6 +90,7 @@ def tabbed(cls, message: str): Args: message (str): The message to print. """ + print(f" {Output().bright_dash} {message}") @classmethod @@ -91,6 +100,7 @@ def header(cls, message: str): Args: message (str): The message to print. """ + print( f"{cls.bright('---')}" f" {message} " @@ -104,6 +114,7 @@ def result(cls, message: str): Args: message (str): The message to print. """ + print(f"{Output().green_plus} {message}") @classmethod @@ -114,6 +125,7 @@ def owned(cls, message: str): Args: message (str): The message to print. """ + print(f"{Output().green_exclaim} {message}") @classmethod @@ -131,8 +143,13 @@ def warn(cls, message: str): """Used to let the user know something that they should not, but unlikely to lead to an exploit. """ + print(f"{Output().yellow_exclaim} {message}") + + ####################### + ## Color Functions ## + ####################### @classmethod def bright(cls, toformat: str): """Highlights the text and returns it. @@ -148,33 +165,22 @@ def bright(cls, toformat: str): return f'{Style.BRIGHT}{toformat}{Style.RESET_ALL}' else: return toformat - + @classmethod - def yellow(cls, toformat: str): - """Makes the text yellow and returns it. - - Args: - toformat (str): Message to format. - - Returns: - (str)): Formatted message. - """ - if cls not in cls._instances or Output().color: - return f'{Fore.YELLOW}{toformat}{Style.RESET_ALL}' - else: - return toformat - - @classmethod - def green(cls, toformat: str): + def text_color(cls, toformat: str, color: str): """Makes the text green and returns it. Args: toformat (str): Message to format. + color (str): Message to color. Either Returns: (str)): Formatted message. """ + if cls not in cls._instances or Output().color: - return f'{Fore.GREEN}{toformat}{Style.RESET_ALL}' + color = color.upper() + color = "Fore." + color + return f'{color}{toformat}{Style.RESET_ALL}' else: - return toformat + return toformat \ No newline at end of file diff --git a/gato/enumerate/enumerate.py b/gato/enumerate/enumerate.py index a33139f..24c9c9f 100644 --- a/gato/enumerate/enumerate.py +++ b/gato/enumerate/enumerate.py @@ -75,7 +75,7 @@ def __setup_user_info(self): if len(self.user_perms["scopes"]): Output.info( "The GitHub Classic PAT has the following scopes: " - f'{Output.yellow(", ".join(self.user_perms["scopes"]))}' + f'{Output.text_color(", ".join(self.user_perms["scopes"]), 'yellow')}' ) else: Output.warn("The token has no scopes!") diff --git a/gato/enumerate/recommender.py b/gato/enumerate/recommender.py index d4a07be..5df0fb5 100644 --- a/gato/enumerate/recommender.py +++ b/gato/enumerate/recommender.py @@ -211,7 +211,7 @@ def print_org_findings(scopes, organization: Organization): Output.owned("The user is an organization owner!") if "admin:org" in scopes: Output.result( - f"The token also has the {Output.yellow('admin:org')} " + f"The token also has the {Output.text_color('admin:org', 'yellow')} " "scope. This token has extensive access to the GitHub" " organization!" ) diff --git a/gato/search/search.py b/gato/search/search.py index b0c326e..9079c2a 100644 --- a/gato/search/search.py +++ b/gato/search/search.py @@ -52,7 +52,7 @@ def __setup_user_info(self): if len(self.user_perms["scopes"]) > 0: Output.info( f"The GitHub Classic PAT has the following scopes: " - f'{Output.yellow(", ".join(self.user_perms["scopes"]))}' + f'{Output.text_color(", ".join(self.user_perms["scopes"]), 'yellow')}' ) else: Output.warn("The token has no scopes!") From 79587df74a957fed2ff99ddbf7f03bdd63951fe8 Mon Sep 17 00:00:00 2001 From: Aleksa Zatezalo Date: Tue, 30 Jul 2024 14:10:34 -0400 Subject: [PATCH 2/3] Coloring reverted in one case. --- gato/cli/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gato/cli/cli.py b/gato/cli/cli.py index 937fa7f..ef31f60 100644 --- a/gato/cli/cli.py +++ b/gato/cli/cli.py @@ -456,7 +456,7 @@ def configure_parser_attack(parser): parser.add_argument( "--file-name", "-fn", default="test", - help=f"Name of yaml file {Output.text_color('without extension', 'red')} that will be\n" + help=f"Name of yaml file {Output.bright('without extension')} that will be\n" "written as part of either attack type. Defaults to 'test'", type=StringType(64) ) From b9e665a24e417df2156e5ffb4b9e9051d0fb3e91 Mon Sep 17 00:00:00 2001 From: Aleksa Zatezalo Date: Tue, 30 Jul 2024 14:45:24 -0400 Subject: [PATCH 3/3] Text coloring functions combined. Quotes changed --- gato/attack/attack.py | 2 +- gato/enumerate/enumerate.py | 2 +- gato/search/search.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gato/attack/attack.py b/gato/attack/attack.py index 0aa2685..fc34ac9 100644 --- a/gato/attack/attack.py +++ b/gato/attack/attack.py @@ -77,7 +77,7 @@ def __setup_user_info(self): ) Output.info( "The GitHub Classic PAT has the following scopes: " - f'{Output.text_color(", ".join(self.user_perms["scopes"]), 'yellow')}' + f'{Output.text_color(", ".join(self.user_perms["scopes"]), "yellow")}' ) return True diff --git a/gato/enumerate/enumerate.py b/gato/enumerate/enumerate.py index 24c9c9f..76f237d 100644 --- a/gato/enumerate/enumerate.py +++ b/gato/enumerate/enumerate.py @@ -75,7 +75,7 @@ def __setup_user_info(self): if len(self.user_perms["scopes"]): Output.info( "The GitHub Classic PAT has the following scopes: " - f'{Output.text_color(", ".join(self.user_perms["scopes"]), 'yellow')}' + f'{Output.text_color(", ".join(self.user_perms["scopes"]), "yellow")}' ) else: Output.warn("The token has no scopes!") diff --git a/gato/search/search.py b/gato/search/search.py index 9079c2a..9a8bca4 100644 --- a/gato/search/search.py +++ b/gato/search/search.py @@ -52,7 +52,7 @@ def __setup_user_info(self): if len(self.user_perms["scopes"]) > 0: Output.info( f"The GitHub Classic PAT has the following scopes: " - f'{Output.text_color(", ".join(self.user_perms["scopes"]), 'yellow')}' + f'{Output.text_color(", ".join(self.user_perms["scopes"]), "yellow")}' ) else: Output.warn("The token has no scopes!")