Exemplo n.º 1
0
class Output:
    LEVELS = ('info', 'warn', 'fail')  # type: Sequence[str]
    COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}

    # Use brighter colors on Windows for better readability.
    if Utils.is_windows():
        COLORS = {'head': 96, 'good': 92, 'warn': 93, 'fail': 91}

    def __init__(self) -> None:
        self.batch = False
        self.verbose = False
        self.use_colors = True
        self.json = False
        self.__level = 0
        self.__colsupport = 'colorama' in sys.modules or os.name == 'posix'

    @property
    def level(self) -> str:
        if self.__level < len(self.LEVELS):
            return self.LEVELS[self.__level]
        return 'unknown'

    @level.setter
    def level(self, name: str) -> None:
        self.__level = self.get_level(name)

    def get_level(self, name: str) -> int:
        cname = 'info' if name == 'good' else name
        if cname not in self.LEVELS:
            return sys.maxsize
        return self.LEVELS.index(cname)

    def sep(self) -> None:
        if not self.batch:
            print()

    @property
    def colors_supported(self) -> bool:
        return self.__colsupport

    @staticmethod
    def _colorized(color: str) -> Callable[[str], None]:
        return lambda x: print(u'{}{}\033[0m'.format(color, x))

    def __getattr__(self, name: str) -> Callable[[str], None]:
        if name == 'head' and self.batch:
            return lambda x: None
        if not self.get_level(name) >= self.__level:
            return lambda x: None
        if self.use_colors and self.colors_supported and name in self.COLORS:
            color = '\033[0;{}m'.format(self.COLORS[name])
            return self._colorized(color)
        else:
            return lambda x: print(u'{}'.format(x))
Exemplo n.º 2
0
def evaluate_policy(aconf: AuditConf,
                    banner: Optional['Banner'],
                    client_host: Optional[str],
                    kex: Optional['SSH2_Kex'] = None) -> bool:

    if aconf.policy is None:
        raise RuntimeError(
            'Internal error: cannot evaluate against null Policy!')

    passed, error_struct, error_str = aconf.policy.evaluate(banner, kex)
    if aconf.json:
        json_struct = {
            'host': aconf.host,
            'policy': aconf.policy.get_name_and_version(),
            'passed': passed,
            'errors': error_struct
        }
        print(json.dumps(json_struct, sort_keys=True))
    else:
        spacing = ''
        if aconf.client_audit:
            print("Client IP: %s" % client_host)
            spacing = "   "  # So the fields below line up with 'Client IP: '.
        else:
            host = aconf.host
            if aconf.port != 22:
                # Check if this is an IPv6 address, as that is printed in a different format.
                if Utils.is_ipv6_address(aconf.host):
                    host = '[%s]:%d' % (aconf.host, aconf.port)
                else:
                    host = '%s:%d' % (aconf.host, aconf.port)

            print("Host:   %s" % host)
        print("Policy: %s%s" % (spacing, aconf.policy.get_name_and_version()))
        print("Result: %s" % spacing, end='')

        # Use these nice unicode characters in the result message, unless we're on Windows (the cmd.exe terminal doesn't display them properly).
        icon_good = "✔ "
        icon_fail = "❌ "
        if Utils.is_windows():
            icon_good = ""
            icon_fail = ""

        if passed:
            out.good("%sPassed" % icon_good)
        else:
            out.fail("%sFailed!" % icon_fail)
            out.warn("\nErrors:\n%s" % error_str)

    return passed
Exemplo n.º 3
0
class OutputBuffer:
    LEVELS: Sequence[str] = ('info', 'warn', 'fail')
    COLORS = {'head': 36, 'good': 32, 'warn': 33, 'fail': 31}

    # Use brighter colors on Windows for better readability.
    if Utils.is_windows():
        COLORS = {'head': 96, 'good': 92, 'warn': 93, 'fail': 91}

    def __init__(self, buffer_output: bool = True) -> None:
        self.buffer_output = buffer_output
        self.buffer: List[str] = []
        self.in_section = False
        self.section: List[str] = []
        self.batch = False
        self.verbose = False
        self.debug = False
        self.use_colors = True
        self.json = False
        self.__level = 0
        self.__is_color_supported = ('colorama' in sys.modules) or (os.name
                                                                    == 'posix')
        self.line_ended = True

    def _print(self, level: str, s: str = '', line_ended: bool = True) -> None:
        '''Saves output to buffer (if in buffered mode), or immediately prints to stdout otherwise.'''

        # If we're logging only 'warn' or above, and this is an 'info', ignore message.
        if self.get_level(level) < self.__level:
            return

        if self.use_colors and self.colors_supported and len(
                s) > 0 and level != 'info':
            s = "\033[0;%dm%s\033[0m" % (self.COLORS[level], s)

        if self.buffer_output:
            # Select which list to add to.  If we are in a 'with' statement, then this goes in the section buffer, otherwise the general buffer.
            buf = self.section if self.in_section else self.buffer

            # Determine if a new line should be added, or if the last line should be appended.
            if not self.line_ended:
                last_entry = -1 if len(buf) > 0 else 0
                buf[last_entry] = buf[last_entry] + s
            else:
                buf.append(s)

            # When False, this tells the next call to append to the last line we just added.
            self.line_ended = line_ended
        else:
            print(s)

    def get_buffer(self) -> str:
        '''Returns all buffered output, then clears the buffer.'''
        self.flush_section()

        buffer_str = "\n".join(self.buffer)
        self.buffer = []
        return buffer_str

    def write(self) -> None:
        '''Writes the output to stdout.'''
        self.flush_section()
        print(self.get_buffer(), flush=True)

    def reset(self) -> None:
        self.flush_section()
        self.get_buffer()

    @property
    def level(self) -> str:
        '''Returns the minimum level for output.'''
        if self.__level < len(self.LEVELS):
            return self.LEVELS[self.__level]
        return 'unknown'

    @level.setter
    def level(self, name: str) -> None:
        '''Sets the minimum level for output (one of: 'info', 'warn', 'fail').'''
        self.__level = self.get_level(name)

    def get_level(self, name: str) -> int:
        cname = 'info' if name == 'good' else name
        if cname not in self.LEVELS:
            return sys.maxsize
        return self.LEVELS.index(cname)

    @property
    def colors_supported(self) -> bool:
        '''Returns True if the system supports color output.'''
        return self.__is_color_supported

    # When used in a 'with' block, the output to goes into a section; this can be sorted separately when add_section_to_buffer() is later called.
    def __enter__(self) -> 'OutputBuffer':
        self.in_section = True
        return self

    def __exit__(self, *args: Any) -> None:
        self.in_section = False

    def flush_section(self, sort_section: bool = False) -> None:
        '''Appends section output (optionally sorting it first) to the end of the buffer, then clears the section output.'''
        if sort_section:
            self.section.sort()

        self.buffer.extend(self.section)
        self.section = []

    def is_section_empty(self) -> bool:
        '''Returns True if the section buffer is empty, otherwise False.'''
        return len(self.section) == 0

    def head(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
        if not self.batch:
            self._print('head', s, line_ended)
        return self

    def fail(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
        self._print('fail', s, line_ended)
        return self

    def warn(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
        self._print('warn', s, line_ended)
        return self

    def info(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
        self._print('info', s, line_ended)
        return self

    def good(self, s: str, line_ended: bool = True) -> 'OutputBuffer':
        self._print('good', s, line_ended)
        return self

    def sep(self) -> 'OutputBuffer':
        if not self.batch:
            self._print('info')
        return self

    def v(self, s: str, write_now: bool = False) -> 'OutputBuffer':
        '''Prints a message if verbose output is enabled.'''
        if self.verbose or self.debug:
            self.info(s)
            if write_now:
                self.write()

        return self

    def d(self, s: str, write_now: bool = False) -> 'OutputBuffer':
        '''Prints a message if verbose output is enabled.'''
        if self.debug:
            self.info(s)
            if write_now:
                self.write()

        return self